From 9ac5e191b8ee00979e13443050b756fcec566b25 Mon Sep 17 00:00:00 2001 From: Giovanni Bussi <giovanni.bussi@gmail.com> Date: Tue, 25 Apr 2017 20:23:23 +0200 Subject: [PATCH] astyle --- src/adjmat/ActionWithInputMatrix.cpp | 116 +- src/adjmat/ActionWithInputMatrix.h | 2 +- src/adjmat/AdjacencyMatrixBase.cpp | 190 +- src/adjmat/AdjacencyMatrixBase.h | 24 +- src/adjmat/AdjacencyMatrixVessel.cpp | 86 +- src/adjmat/AdjacencyMatrixVessel.h | 10 +- src/adjmat/AlignedMatrixBase.cpp | 80 +- src/adjmat/ClusterAnalysisBase.cpp | 24 +- src/adjmat/ClusterAnalysisBase.h | 2 +- src/adjmat/ClusterDiameter.cpp | 66 +- src/adjmat/ClusterDistribution.cpp | 116 +- src/adjmat/ClusterProperties.cpp | 72 +- src/adjmat/ClusterSize.cpp | 44 +- src/adjmat/ClusterWithSurface.cpp | 80 +- src/adjmat/ClusteringBase.cpp | 62 +- src/adjmat/ClusteringBase.h | 8 +- src/adjmat/ContactAlignedMatrix.cpp | 86 +- src/adjmat/ContactMatrix.cpp | 48 +- src/adjmat/DFSClustering.cpp | 104 +- src/adjmat/DumpGraph.cpp | 72 +- src/adjmat/HbondMatrix.cpp | 142 +- src/adjmat/MatrixColumnSums.cpp | 64 +- src/adjmat/MatrixRowSums.cpp | 46 +- src/adjmat/OutputCluster.cpp | 172 +- src/adjmat/SMACMatrix.cpp | 102 +- src/adjmat/Sprint.cpp | 226 +- src/adjmat/TopologyMatrix.cpp | 254 +- src/analysis/Analysis.cpp | 310 +-- src/analysis/Analysis.h | 28 +- src/analysis/AnalysisWithLandmarks.cpp | 32 +- src/analysis/AnalysisWithLandmarks.h | 8 +- src/analysis/Average.cpp | 78 +- src/analysis/AverageVessel.cpp | 20 +- src/analysis/AverageVessel.h | 16 +- .../ClassicalMultiDimensionalScaling.cpp | 122 +- src/analysis/ClassicalScaling.cpp | 50 +- src/analysis/Commit.cpp | 80 +- src/analysis/Histogram.cpp | 520 ++-- src/analysis/LandmarkRegister.cpp | 28 +- src/analysis/LandmarkRegister.h | 6 +- src/analysis/LandmarkSelectionBase.cpp | 82 +- src/analysis/LandmarkSelectionBase.h | 24 +- src/analysis/PCA.cpp | 156 +- src/analysis/SelectAllFrames.cpp | 6 +- src/bias/ABMD.cpp | 60 +- src/bias/Bias.cpp | 44 +- src/bias/Bias.h | 14 +- src/bias/BiasValue.cpp | 40 +- src/bias/ExtendedLagrangian.cpp | 88 +- src/bias/External.cpp | 50 +- src/bias/LWalls.cpp | 52 +- src/bias/MetaD.cpp | 754 +++--- src/bias/Metainference.cpp | 234 +- src/bias/MovingRestraint.cpp | 106 +- src/bias/PBMetaD.cpp | 1038 ++++---- src/bias/Restraint.cpp | 44 +- src/bias/ReweightBase.cpp | 22 +- src/bias/ReweightBase.h | 12 +- src/bias/ReweightBias.cpp | 24 +- src/bias/ReweightMetad.cpp | 22 +- src/bias/ReweightTemperature.cpp | 64 +- src/bias/UWalls.cpp | 48 +- src/cltools/CLTool.h | 6 +- src/cltools/Driver.cpp | 948 ++++---- src/cltools/DriverDouble.cpp | 2 +- src/cltools/DriverFloat.cpp | 4 +- src/cltools/GenTemplate.cpp | 44 +- src/cltools/Info.cpp | 50 +- src/cltools/Manual.cpp | 44 +- src/cltools/SimpleMD.cpp | 774 +++--- src/cltools/SumHills.cpp | 633 ++--- src/cltools/kT.cpp | 28 +- src/colvar/Angle.cpp | 22 +- src/colvar/CS2Backbone.cpp | 773 +++--- src/colvar/Cell.cpp | 20 +- src/colvar/Colvar.h | 6 +- src/colvar/Constant.cpp | 26 +- src/colvar/ContactMap.cpp | 292 +-- src/colvar/Coordination.cpp | 28 +- src/colvar/CoordinationBase.cpp | 188 +- src/colvar/CoordinationBase.h | 6 +- src/colvar/DHEnergy.cpp | 68 +- src/colvar/DRMSD.cpp | 76 +- src/colvar/Dimer.cpp | 375 +-- src/colvar/Dipole.cpp | 104 +- src/colvar/Distance.cpp | 30 +- src/colvar/ERMSD.cpp | 82 +- src/colvar/Energy.cpp | 18 +- src/colvar/Fake.cpp | 92 +- src/colvar/FretEfficiency.cpp | 22 +- src/colvar/Gyration.cpp | 254 +- src/colvar/Implicit.cpp | 2130 ++++++++--------- src/colvar/Jcoupling.cpp | 474 ++-- src/colvar/MultiRMSD.cpp | 42 +- src/colvar/NOE.cpp | 86 +- src/colvar/PCARMSD.cpp | 186 +- src/colvar/PRE.cpp | 92 +- src/colvar/PathMSD.cpp | 30 +- src/colvar/PathMSDBase.cpp | 174 +- src/colvar/PathMSDBase.h | 44 +- src/colvar/Position.cpp | 26 +- src/colvar/PropertyMap.cpp | 84 +- src/colvar/Puckering.cpp | 330 +-- src/colvar/RDC.cpp | 108 +- src/colvar/RMSD.cpp | 80 +- src/colvar/Template.cpp | 18 +- src/colvar/Torsion.cpp | 50 +- src/colvar/Volume.cpp | 10 +- src/config/Config.h | 4 +- src/config/Config.inc.in | 81 +- src/core/Action.cpp | 136 +- src/core/Action.h | 134 +- src/core/ActionAtomistic.cpp | 208 +- src/core/ActionAtomistic.h | 60 +- src/core/ActionPilot.cpp | 22 +- src/core/ActionPilot.h | 6 +- src/core/ActionRegister.cpp | 82 +- src/core/ActionRegister.h | 8 +- src/core/ActionSet.cpp | 18 +- src/core/ActionSet.h | 14 +- src/core/ActionSetup.cpp | 6 +- src/core/ActionSetup.h | 8 +- src/core/ActionWithArguments.cpp | 390 +-- src/core/ActionWithArguments.h | 28 +- src/core/ActionWithValue.cpp | 136 +- src/core/ActionWithValue.h | 54 +- src/core/ActionWithVirtualAtom.cpp | 52 +- src/core/ActionWithVirtualAtom.h | 14 +- src/core/Atoms.cpp | 246 +- src/core/Atoms.h | 50 +- src/core/CLTool.cpp | 216 +- src/core/CLTool.h | 74 +- src/core/CLToolMain.cpp | 176 +- src/core/CLToolMain.h | 12 +- src/core/CLToolRegister.cpp | 50 +- src/core/CLToolRegister.h | 6 +- src/core/Colvar.cpp | 46 +- src/core/Colvar.h | 24 +- src/core/ExchangePatterns.cpp | 32 +- src/core/ExchangePatterns.h | 8 +- src/core/FlexibleBin.cpp | 566 ++--- src/core/FlexibleBin.h | 56 +- src/core/GREX.cpp | 24 +- src/core/GREX.h | 2 +- src/core/MDAtoms.cpp | 76 +- src/core/MDAtoms.h | 2 +- src/core/PlumedMain.cpp | 838 +++---- src/core/PlumedMain.h | 190 +- src/core/PlumedMainInitializer.cpp | 16 +- src/core/SetupMolInfo.cpp | 192 +- src/core/SetupMolInfo.h | 6 +- src/core/TargetDist.cpp | 36 +- src/core/TargetDist.h | 6 +- src/core/Value.cpp | 88 +- src/core/Value.h | 92 +- src/core/WithCmd.h | 8 +- src/crystallization/BondOrientation.cpp | 50 +- src/crystallization/CubicHarmonicBase.cpp | 140 +- src/crystallization/CubicHarmonicBase.h | 6 +- src/crystallization/Fccubic.cpp | 34 +- src/crystallization/Gradient.cpp | 108 +- src/crystallization/Gradient.h | 4 +- src/crystallization/GradientVessel.cpp | 200 +- .../InterMolecularTorsions.cpp | 126 +- src/crystallization/LocalSteinhardt.h | 36 +- src/crystallization/MoleculeOrientation.cpp | 102 +- src/crystallization/MoleculePlane.cpp | 70 +- src/crystallization/OrientationSphere.cpp | 138 +- src/crystallization/OrientationSphere.h | 4 +- src/crystallization/Q3.cpp | 44 +- src/crystallization/Q4.cpp | 42 +- src/crystallization/Q6.cpp | 42 +- src/crystallization/SMAC.cpp | 122 +- src/crystallization/SimpleCubic.cpp | 30 +- src/crystallization/Steinhardt.cpp | 182 +- src/crystallization/Tetrahedral.cpp | 76 +- src/crystallization/VectorMean.cpp | 54 +- src/crystallization/VectorMultiColvar.cpp | 62 +- src/crystallization/VectorMultiColvar.h | 14 +- src/crystallization/VectorSum.cpp | 54 +- src/eds/EDS.cpp | 1051 ++++---- src/function/Combine.cpp | 38 +- src/function/Ensemble.cpp | 104 +- src/function/FuncPathMSD.cpp | 266 +- src/function/FuncSumHills.cpp | 782 +++--- src/function/Function.cpp | 46 +- src/function/Function.h | 16 +- src/function/LocalEnsemble.cpp | 34 +- src/function/Matheval.cpp | 44 +- src/function/Piecewise.cpp | 54 +- src/function/Sort.cpp | 24 +- src/function/Stats.cpp | 54 +- src/function/Target.cpp | 52 +- src/generic/Debug.cpp | 34 +- src/generic/DumpAtoms.cpp | 88 +- src/generic/DumpDerivatives.cpp | 40 +- src/generic/DumpForces.cpp | 32 +- src/generic/DumpMassCharge.cpp | 26 +- src/generic/DumpProjections.cpp | 36 +- src/generic/EffectiveEnergyDrift.cpp | 78 +- src/generic/FitToTemplate.cpp | 166 +- src/generic/Flush.cpp | 16 +- src/generic/Group.cpp | 46 +- src/generic/Include.cpp | 12 +- src/generic/Print.cpp | 62 +- src/generic/RandomExchanges.cpp | 12 +- src/generic/Read.cpp | 178 +- src/generic/ResetCell.cpp | 80 +- src/generic/Time.cpp | 18 +- src/generic/UpdateIf.cpp | 34 +- src/generic/WholeMolecules.cpp | 70 +- src/generic/WrapAround.cpp | 32 +- src/gridtools/ActionWithGrid.cpp | 58 +- src/gridtools/ActionWithGrid.h | 2 +- src/gridtools/ActionWithInputGrid.cpp | 38 +- src/gridtools/ActionWithInputGrid.h | 8 +- src/gridtools/ActionWithIntegral.cpp | 22 +- src/gridtools/ActionWithIntegral.h | 4 +- src/gridtools/AverageOnGrid.cpp | 26 +- src/gridtools/AverageOnGrid.h | 2 +- src/gridtools/ContourFindingBase.cpp | 10 +- src/gridtools/ContourFindingBase.h | 4 +- src/gridtools/ConvertToFES.cpp | 40 +- src/gridtools/DumpCube.cpp | 50 +- src/gridtools/DumpGrid.cpp | 108 +- src/gridtools/FindContour.cpp | 158 +- src/gridtools/FindContourSurface.cpp | 234 +- src/gridtools/FindSphericalContour.cpp | 78 +- src/gridtools/FourierTransform.cpp | 254 +- src/gridtools/GridPrintingBase.cpp | 28 +- src/gridtools/GridPrintingBase.h | 4 +- src/gridtools/GridToXYZ.cpp | 52 +- src/gridtools/GridVessel.cpp | 366 +-- src/gridtools/GridVessel.h | 168 +- src/gridtools/HistogramOnGrid.cpp | 252 +- src/gridtools/HistogramOnGrid.h | 2 +- src/gridtools/IntegrateGrid.cpp | 6 +- src/gridtools/InterpolateGrid.cpp | 44 +- src/main/main.cpp | 6 +- src/manyrestraints/LWalls.cpp | 26 +- src/manyrestraints/ManyRestraintsBase.cpp | 34 +- src/manyrestraints/ManyRestraintsBase.h | 26 +- src/manyrestraints/UWalls.cpp | 28 +- src/mapping/Mapping.cpp | 204 +- src/mapping/Mapping.h | 32 +- src/mapping/PCAVars.cpp | 316 +-- src/mapping/Path.cpp | 68 +- src/mapping/PathBase.cpp | 30 +- src/mapping/PathBase.h | 4 +- src/mapping/PathReparameterization.cpp | 148 +- src/mapping/PathReparameterization.h | 2 +- src/mapping/PathTools.cpp | 292 +-- src/mapping/PropertyMap.cpp | 32 +- src/mapping/SpathVessel.cpp | 28 +- src/mapping/TrigonometricPathVessel.cpp | 210 +- src/mapping/TrigonometricPathVessel.h | 4 +- src/mapping/ZpathVessel.cpp | 16 +- src/multicolvar/ActionVolume.cpp | 38 +- src/multicolvar/ActionVolume.h | 10 +- src/multicolvar/AlphaBeta.cpp | 70 +- src/multicolvar/Angles.cpp | 116 +- src/multicolvar/AtomValuePack.cpp | 76 +- src/multicolvar/AtomValuePack.h | 56 +- src/multicolvar/Bridge.cpp | 90 +- .../BridgedMultiColvarFunction.cpp | 62 +- src/multicolvar/BridgedMultiColvarFunction.h | 38 +- src/multicolvar/CatomPack.cpp | 6 +- src/multicolvar/CatomPack.h | 14 +- src/multicolvar/CenterOfMultiColvar.cpp | 166 +- src/multicolvar/CoordinationNumbers.cpp | 70 +- src/multicolvar/Density.cpp | 34 +- src/multicolvar/DihedralCorrelation.cpp | 36 +- src/multicolvar/DistanceFromContour.cpp | 240 +- src/multicolvar/Distances.cpp | 124 +- src/multicolvar/DumpMultiColvar.cpp | 52 +- src/multicolvar/FilterBetween.cpp | 78 +- src/multicolvar/FilterLessThan.cpp | 58 +- src/multicolvar/FilterMoreThan.cpp | 62 +- src/multicolvar/InPlaneDistances.cpp | 74 +- src/multicolvar/LocalAverage.cpp | 238 +- src/multicolvar/MultiColvarBase.cpp | 1388 +++++------ src/multicolvar/MultiColvarBase.h | 62 +- src/multicolvar/MultiColvarCombine.cpp | 40 +- src/multicolvar/MultiColvarDensity.cpp | 216 +- src/multicolvar/MultiColvarFilter.cpp | 58 +- src/multicolvar/MultiColvarFilter.h | 2 +- src/multicolvar/MultiColvarProduct.cpp | 38 +- src/multicolvar/NumberOfLinks.cpp | 88 +- src/multicolvar/Torsions.cpp | 36 +- src/multicolvar/VolumeAround.cpp | 60 +- src/multicolvar/VolumeCavity.cpp | 218 +- src/multicolvar/VolumeGradientBase.cpp | 164 +- src/multicolvar/VolumeGradientBase.h | 36 +- src/multicolvar/VolumeInCylinder.cpp | 66 +- src/multicolvar/VolumeInSphere.cpp | 38 +- src/multicolvar/VolumeTetrapore.cpp | 226 +- src/multicolvar/XAngle.cpp | 76 +- src/multicolvar/XDistances.cpp | 110 +- src/multicolvar/XYDistances.cpp | 98 +- src/multicolvar/XYTorsion.cpp | 118 +- src/reference/ArgumentOnlyDistance.cpp | 10 +- src/reference/ArgumentOnlyDistance.h | 4 +- src/reference/DRMSD.cpp | 90 +- src/reference/DRMSD.h | 4 +- src/reference/Direction.cpp | 30 +- src/reference/Direction.h | 10 +- src/reference/DotProductDistance.cpp | 12 +- src/reference/EuclideanDistance.cpp | 4 +- src/reference/FakeFrame.h | 8 +- src/reference/IntermolecularDRMSD.cpp | 30 +- src/reference/IntramolecularDRMSD.cpp | 26 +- src/reference/MahalanobisDistance.cpp | 4 +- src/reference/MetricRegister.cpp | 18 +- src/reference/MetricRegister.h | 34 +- src/reference/MultiDomainRMSD.cpp | 242 +- src/reference/MultiDomainRMSD.h | 4 +- src/reference/MultiReferenceBase.cpp | 52 +- src/reference/MultiReferenceBase.h | 34 +- src/reference/NormalizedEuclideanDistance.cpp | 4 +- src/reference/OptimalRMSD.cpp | 74 +- src/reference/PointWiseMapping.cpp | 66 +- src/reference/PointWiseMapping.h | 18 +- src/reference/RMSDBase.cpp | 10 +- src/reference/RMSDBase.h | 2 +- src/reference/ReferenceArguments.cpp | 268 +-- src/reference/ReferenceArguments.h | 20 +- src/reference/ReferenceAtoms.cpp | 112 +- src/reference/ReferenceAtoms.h | 28 +- src/reference/ReferenceConfiguration.cpp | 128 +- src/reference/ReferenceConfiguration.h | 66 +- src/reference/ReferenceValuePack.cpp | 74 +- src/reference/ReferenceValuePack.h | 36 +- src/reference/SimpleRMSD.cpp | 36 +- src/reference/SingleDomainRMSD.cpp | 40 +- src/reference/SingleDomainRMSD.h | 6 +- src/secondarystructure/AlphaRMSD.cpp | 50 +- src/secondarystructure/AntibetaRMSD.cpp | 136 +- src/secondarystructure/ParabetaRMSD.cpp | 134 +- .../SecondaryStructureRMSD.cpp | 182 +- .../SecondaryStructureRMSD.h | 10 +- src/setup/Load.cpp | 12 +- src/setup/MolInfo.cpp | 14 +- src/setup/Restart.cpp | 12 +- src/setup/Units.cpp | 14 +- src/tools/Angle.cpp | 62 +- src/tools/Angle.h | 4 +- src/tools/AtomNumber.h | 32 +- src/tools/BiasRepresentation.cpp | 440 ++-- src/tools/BiasRepresentation.h | 122 +- src/tools/Brent1DRootSearch.h | 92 +- src/tools/Citations.cpp | 14 +- src/tools/Citations.h | 4 +- src/tools/Communicator.cpp | 88 +- src/tools/Communicator.h | 88 +- src/tools/CubicInterpolation.cpp | 251 +- src/tools/CubicInterpolation.h | 4 +- src/tools/DLLoader.cpp | 16 +- src/tools/DLLoader.h | 4 +- src/tools/DynamicList.h | 124 +- src/tools/ERMSD.cpp | 546 ++--- src/tools/ERMSD.h | 34 +- src/tools/Exception.cpp | 12 +- src/tools/Exception.h | 10 +- src/tools/FileBase.cpp | 34 +- src/tools/FileBase.h | 14 +- src/tools/Grid.cpp | 1370 +++++------ src/tools/Grid.h | 290 +-- src/tools/HistogramBead.cpp | 200 +- src/tools/HistogramBead.h | 74 +- src/tools/IFile.cpp | 126 +- src/tools/IFile.h | 26 +- src/tools/KernelFunctions.cpp | 304 +-- src/tools/KernelFunctions.h | 22 +- src/tools/Keywords.cpp | 766 +++--- src/tools/Keywords.h | 22 +- src/tools/LatticeReduction.cpp | 74 +- src/tools/LatticeReduction.h | 6 +- src/tools/LinkCells.cpp | 104 +- src/tools/LinkCells.h | 4 +- src/tools/Log.h | 2 +- src/tools/LoopUnroller.h | 32 +- src/tools/Matrix.h | 520 ++-- src/tools/MatrixSquareBracketsAccess.h | 28 +- src/tools/Minimise1DBrent.h | 212 +- src/tools/MinimiseBase.h | 34 +- src/tools/MolDataClass.cpp | 300 +-- src/tools/MolDataClass.h | 6 +- src/tools/MultiValue.cpp | 86 +- src/tools/MultiValue.h | 46 +- src/tools/NeighborList.cpp | 176 +- src/tools/NeighborList.h | 16 +- src/tools/OFile.cpp | 210 +- src/tools/OFile.h | 38 +- src/tools/OpenMP.cpp | 6 +- src/tools/OpenMP.h | 20 +- src/tools/PDB.cpp | 194 +- src/tools/PDB.h | 16 +- src/tools/Pbc.cpp | 160 +- src/tools/Pbc.h | 8 +- src/tools/RMSD.cpp | 1226 +++++----- src/tools/RMSD.h | 406 ++-- src/tools/Random.cpp | 162 +- src/tools/Random.h | 66 +- src/tools/RootFindingBase.h | 8 +- src/tools/Stopwatch.cpp | 28 +- src/tools/Stopwatch.h | 12 +- src/tools/SwitchingFunction.cpp | 218 +- src/tools/SwitchingFunction.h | 6 +- src/tools/Tensor.cpp | 6 +- src/tools/Tensor.h | 176 +- src/tools/Tools.cpp | 186 +- src/tools/Tools.h | 62 +- src/tools/Torsion.cpp | 20 +- src/tools/Torsion.h | 4 +- src/tools/Units.cpp | 46 +- src/tools/Units.h | 24 +- src/tools/Vector.cpp | 10 +- src/tools/Vector.h | 72 +- src/vatom/ActionWithVirtualAtom.h | 6 +- src/vatom/COM.cpp | 30 +- src/vatom/Center.cpp | 38 +- src/vatom/FixedAtom.cpp | 10 +- src/vatom/Ghost.cpp | 84 +- src/vesselbase/ActionWithAveraging.cpp | 102 +- src/vesselbase/ActionWithAveraging.h | 18 +- src/vesselbase/ActionWithInputVessel.cpp | 48 +- src/vesselbase/ActionWithInputVessel.h | 8 +- src/vesselbase/ActionWithVessel.cpp | 286 +-- src/vesselbase/ActionWithVessel.h | 40 +- src/vesselbase/AltMin.cpp | 22 +- src/vesselbase/AveragingVessel.cpp | 20 +- src/vesselbase/AveragingVessel.h | 54 +- src/vesselbase/Between.cpp | 34 +- src/vesselbase/BridgeVessel.cpp | 148 +- src/vesselbase/BridgeVessel.h | 10 +- src/vesselbase/FunctionVessel.cpp | 74 +- src/vesselbase/FunctionVessel.h | 4 +- src/vesselbase/Highest.cpp | 14 +- src/vesselbase/Histogram.cpp | 16 +- src/vesselbase/LessThan.cpp | 28 +- src/vesselbase/LessThan.h | 4 +- src/vesselbase/Lowest.cpp | 14 +- src/vesselbase/Max.cpp | 20 +- src/vesselbase/Mean.cpp | 10 +- src/vesselbase/Min.cpp | 22 +- src/vesselbase/Moments.cpp | 156 +- src/vesselbase/MoreThan.cpp | 22 +- src/vesselbase/OrderingVessel.cpp | 40 +- src/vesselbase/OrderingVessel.h | 4 +- src/vesselbase/ShortcutVessel.cpp | 14 +- src/vesselbase/ShortcutVessel.h | 12 +- src/vesselbase/StoreDataVessel.cpp | 144 +- src/vesselbase/StoreDataVessel.h | 66 +- src/vesselbase/Sum.cpp | 12 +- src/vesselbase/ValueVessel.cpp | 44 +- src/vesselbase/ValueVessel.h | 8 +- src/vesselbase/Vessel.cpp | 114 +- src/vesselbase/Vessel.h | 80 +- src/vesselbase/VesselRegister.cpp | 34 +- src/vesselbase/VesselRegister.h | 6 +- src/wrapper/Plumed.c | 158 +- src/wrapper/Plumed.h | 250 +- 462 files changed, 24372 insertions(+), 24348 deletions(-) diff --git a/src/adjmat/ActionWithInputMatrix.cpp b/src/adjmat/ActionWithInputMatrix.cpp index c0acb3195..5aed42c85 100644 --- a/src/adjmat/ActionWithInputMatrix.cpp +++ b/src/adjmat/ActionWithInputMatrix.cpp @@ -29,43 +29,43 @@ namespace PLMD { namespace adjmat { -void ActionWithInputMatrix::registerKeywords( Keywords& keys ){ - MultiColvarBase::registerKeywords( keys ); - keys.add("compulsory","MATRIX","the action that calcualtes the adjacency matrix vessel we would like to analyse"); +void ActionWithInputMatrix::registerKeywords( Keywords& keys ) { + MultiColvarBase::registerKeywords( keys ); + keys.add("compulsory","MATRIX","the action that calcualtes the adjacency matrix vessel we would like to analyse"); } ActionWithInputMatrix::ActionWithInputMatrix(const ActionOptions& ao): -Action(ao), -MultiColvarBase(ao), -mymatrix(NULL) + Action(ao), + MultiColvarBase(ao), + mymatrix(NULL) { - matsums=true; - if( keywords.exists("MATRIX") ){ - std::vector<AtomNumber> fake_atoms; - if( !parseMultiColvarAtomList("MATRIX",-1,fake_atoms ) ) error("unable to interpret input matrix"); - if( mybasemulticolvars.size()!=1 ) error("should be exactly one matrix input"); - - // Retrieve the adjacency matrix of interest - for(unsigned i=0;i<mybasemulticolvars[0]->getNumberOfVessels();++i){ - mymatrix = dynamic_cast<AdjacencyMatrixVessel*>( mybasemulticolvars[0]->getPntrToVessel(i) ); - if( mymatrix ) break ; - } - if( !mymatrix ) error( mybasemulticolvars[0]->getLabel() + " does not calculate an adjacency matrix"); - - atom_lab.resize(0); unsigned nnodes; // Delete all the atom labels that have been created - if( mymatrix->undirectedGraph() ) nnodes = (mymatrix->function)->ablocks[0].size(); - else nnodes = (mymatrix->function)->ablocks[0].size() + (mymatrix->function)->ablocks[1].size(); - for(unsigned i=0;i<nnodes;++i) atom_lab.push_back( std::pair<unsigned,unsigned>( 1, i ) ); + matsums=true; + if( keywords.exists("MATRIX") ) { + std::vector<AtomNumber> fake_atoms; + if( !parseMultiColvarAtomList("MATRIX",-1,fake_atoms ) ) error("unable to interpret input matrix"); + if( mybasemulticolvars.size()!=1 ) error("should be exactly one matrix input"); + + // Retrieve the adjacency matrix of interest + for(unsigned i=0; i<mybasemulticolvars[0]->getNumberOfVessels(); ++i) { + mymatrix = dynamic_cast<AdjacencyMatrixVessel*>( mybasemulticolvars[0]->getPntrToVessel(i) ); + if( mymatrix ) break ; + } + if( !mymatrix ) error( mybasemulticolvars[0]->getLabel() + " does not calculate an adjacency matrix"); + + atom_lab.resize(0); unsigned nnodes; // Delete all the atom labels that have been created + if( mymatrix->undirectedGraph() ) nnodes = (mymatrix->function)->ablocks[0].size(); + else nnodes = (mymatrix->function)->ablocks[0].size() + (mymatrix->function)->ablocks[1].size(); + for(unsigned i=0; i<nnodes; ++i) atom_lab.push_back( std::pair<unsigned,unsigned>( 1, i ) ); } } unsigned ActionWithInputMatrix::getNumberOfDerivatives() { - return (mymatrix->function)->getNumberOfDerivatives(); + return (mymatrix->function)->getNumberOfDerivatives(); } unsigned ActionWithInputMatrix::getNumberOfNodes() const { - return (mymatrix->function)->ablocks[0].size(); + return (mymatrix->function)->ablocks[0].size(); } AdjacencyMatrixVessel* ActionWithInputMatrix::getAdjacencyVessel() const { @@ -73,27 +73,27 @@ AdjacencyMatrixVessel* ActionWithInputMatrix::getAdjacencyVessel() const { } AtomNumber ActionWithInputMatrix::getAbsoluteIndexOfCentralAtom(const unsigned& i) const { - return (mymatrix->function)->getAbsoluteIndexOfCentralAtom(i); + return (mymatrix->function)->getAbsoluteIndexOfCentralAtom(i); } double ActionWithInputMatrix::retrieveConnectionValue( const unsigned& i, const unsigned& j, std::vector<double>& vals ) const { if( !mymatrix->matrixElementIsActive( i, j ) ) return 0; unsigned myelem = mymatrix->getStoreIndexFromMatrixIndices( i, j ); - + unsigned vi; double df; - mymatrix->retrieveValueWithIndex( myelem, false, vals ); + mymatrix->retrieveValueWithIndex( myelem, false, vals ); return vals[0]*vals[1]; // (mymatrix->function)->transformStoredValues( vals, vi, df ); } void ActionWithInputMatrix::getInputData( const unsigned& ind, const bool& normed, const multicolvar::AtomValuePack& myatoms, std::vector<double>& orient0 ) const { - if( (mymatrix->function)->mybasemulticolvars.size()==0 ){ - std::vector<double> tvals( mymatrix->getNumberOfComponents() ); orient0.assign(orient0.size(),0); - for(unsigned i=0;i<mymatrix->getNumberOfColumns();++i){ - if( mymatrix->undirectedGraph() && ind==i ) continue; - orient0[1]+=retrieveConnectionValue( ind, i, tvals ); - } - orient0[0]=1.0; return; - } + if( (mymatrix->function)->mybasemulticolvars.size()==0 ) { + std::vector<double> tvals( mymatrix->getNumberOfComponents() ); orient0.assign(orient0.size(),0); + for(unsigned i=0; i<mymatrix->getNumberOfColumns(); ++i) { + if( mymatrix->undirectedGraph() && ind==i ) continue; + orient0[1]+=retrieveConnectionValue( ind, i, tvals ); + } + orient0[0]=1.0; return; + } (mymatrix->function)->getInputData( ind, normed, myatoms, orient0 ); } @@ -102,33 +102,33 @@ void ActionWithInputMatrix::addConnectionDerivatives( const unsigned& i, const u unsigned myelem = mymatrix->getStoreIndexFromMatrixIndices( i, j ); // Get derivatives and add mymatrix->retrieveDerivatives( myelem, false, myvals ); - for(unsigned jd=0;jd<myvals.getNumberActive();++jd){ - unsigned ider=myvals.getActiveIndex(jd); - myvout.addDerivative( 1, ider, myvals.getDerivative( 1, ider ) ); + for(unsigned jd=0; jd<myvals.getNumberActive(); ++jd) { + unsigned ider=myvals.getActiveIndex(jd); + myvout.addDerivative( 1, ider, myvals.getDerivative( 1, ider ) ); } } MultiValue& ActionWithInputMatrix::getInputDerivatives( const unsigned& ind, const bool& normed, const multicolvar::AtomValuePack& myatoms ) const { - if( (mymatrix->function)->mybasemulticolvars.size()==0 ){ - MultiValue& myder=mymatrix->getTemporyMultiValue(0); - if( myder.getNumberOfValues()!=2 || myder.getNumberOfDerivatives()!=(mymatrix->function)->getNumberOfDerivatives() ){ - myder.resize( 2, (mymatrix->function)->getNumberOfDerivatives() ); - } - myder.clearAll(); - MultiValue myvals( (mymatrix->function)->getNumberOfQuantities(), (mymatrix->function)->getNumberOfDerivatives() ); - for(unsigned i=0;i<mymatrix->getNumberOfColumns();++i){ - if( mymatrix->undirectedGraph() && ind==i ) continue; - addConnectionDerivatives( ind, i, myvals, myder ); - } - myder.updateDynamicList(); return myder; - } - return (mymatrix->function)->getInputDerivatives( ind, normed, myatoms ); + if( (mymatrix->function)->mybasemulticolvars.size()==0 ) { + MultiValue& myder=mymatrix->getTemporyMultiValue(0); + if( myder.getNumberOfValues()!=2 || myder.getNumberOfDerivatives()!=(mymatrix->function)->getNumberOfDerivatives() ) { + myder.resize( 2, (mymatrix->function)->getNumberOfDerivatives() ); + } + myder.clearAll(); + MultiValue myvals( (mymatrix->function)->getNumberOfQuantities(), (mymatrix->function)->getNumberOfDerivatives() ); + for(unsigned i=0; i<mymatrix->getNumberOfColumns(); ++i) { + if( mymatrix->undirectedGraph() && ind==i ) continue; + addConnectionDerivatives( ind, i, myvals, myder ); + } + myder.updateDynamicList(); return myder; + } + return (mymatrix->function)->getInputDerivatives( ind, normed, myatoms ); } unsigned ActionWithInputMatrix::getNumberOfNodeTypes() const { unsigned size = (mymatrix->function)->mybasemulticolvars.size(); if( size==0 ) return 1; - return size; + return size; } unsigned ActionWithInputMatrix::getNumberOfQuantities() const { @@ -137,13 +137,13 @@ unsigned ActionWithInputMatrix::getNumberOfQuantities() const { } unsigned ActionWithInputMatrix::getNumberOfAtomsInGroup( const unsigned& igrp ) const { - plumed_dbg_assert( igrp<(mymatrix->function)->mybasemulticolvars.size() ); - return (mymatrix->function)->mybasemulticolvars[igrp]->getFullNumberOfTasks(); + plumed_dbg_assert( igrp<(mymatrix->function)->mybasemulticolvars.size() ); + return (mymatrix->function)->mybasemulticolvars[igrp]->getFullNumberOfTasks(); } multicolvar::MultiColvarBase* ActionWithInputMatrix::getBaseMultiColvar( const unsigned& igrp ) const { - plumed_dbg_assert( igrp<(mymatrix->function)->mybasemulticolvars.size() ); - return (mymatrix->function)->mybasemulticolvars[igrp]; + plumed_dbg_assert( igrp<(mymatrix->function)->mybasemulticolvars.size() ); + return (mymatrix->function)->mybasemulticolvars[igrp]; } Vector ActionWithInputMatrix::getPositionOfAtomForLinkCells( const unsigned& iatom ) const { diff --git a/src/adjmat/ActionWithInputMatrix.h b/src/adjmat/ActionWithInputMatrix.h index 55c2567ea..994f5ff24 100644 --- a/src/adjmat/ActionWithInputMatrix.h +++ b/src/adjmat/ActionWithInputMatrix.h @@ -57,7 +57,7 @@ public: virtual unsigned getNumberOfDerivatives(); /// Get the number of rows/cols in the adjacency matrix vessel virtual unsigned getNumberOfNodes() const ; - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } virtual unsigned getNumberOfQuantities() const ; /// virtual AtomNumber getAbsoluteIndexOfCentralAtom(const unsigned& i) const ; diff --git a/src/adjmat/AdjacencyMatrixBase.cpp b/src/adjmat/AdjacencyMatrixBase.cpp index 4f9844f9b..9f6cc8de7 100644 --- a/src/adjmat/AdjacencyMatrixBase.cpp +++ b/src/adjmat/AdjacencyMatrixBase.cpp @@ -29,73 +29,73 @@ namespace PLMD { namespace adjmat { -void AdjacencyMatrixBase::registerKeywords( Keywords& keys ){ +void AdjacencyMatrixBase::registerKeywords( Keywords& keys ) { multicolvar::MultiColvarBase::registerKeywords( keys ); keys.remove("LOWMEM"); keys.use("HIGHMEM"); } AdjacencyMatrixBase::AdjacencyMatrixBase(const ActionOptions& ao): -Action(ao), -MultiColvarBase(ao), -connect_id(0), -no_third_dim_accum(true), -mat(NULL) + Action(ao), + MultiColvarBase(ao), + connect_id(0), + no_third_dim_accum(true), + mat(NULL) { log<<" Bibliography "<<plumed.cite("Tribello, Giberti, Sosso, Salvalaglio and Parrinello, J. Chem. Theory Comput. 13, 1317 (2017)")<<"\n"; } -void AdjacencyMatrixBase::parseConnectionDescriptions( const std::string& key, const bool& multiple, const unsigned& nrow_t ){ - if( getNumberOfNodeTypes()==1 || (getNumberOfNodeTypes()==2 && nrow_t==1) ){ - std::vector<std::string> sw; - if( !multiple ){ - sw.resize(1); parse(key,sw[0]); - if(sw[0].length()==0) error("could not find " + key + " keyword"); - } else { - std::string input; - for(int i=1;;i++){ - if( !parseNumbered(key, i, input ) ) break; - sw.push_back( input ); - } +void AdjacencyMatrixBase::parseConnectionDescriptions( const std::string& key, const bool& multiple, const unsigned& nrow_t ) { + if( getNumberOfNodeTypes()==1 || (getNumberOfNodeTypes()==2 && nrow_t==1) ) { + std::vector<std::string> sw; + if( !multiple ) { + sw.resize(1); parse(key,sw[0]); + if(sw[0].length()==0) error("could not find " + key + " keyword"); + } else { + std::string input; + for(int i=1;; i++) { + if( !parseNumbered(key, i, input ) ) break; + sw.push_back( input ); } - setupConnector( connect_id, 0, 0, sw ); + } + setupConnector( connect_id, 0, 0, sw ); } else { - if( multiple ) error("keyword " + key + " does not work with multiple input strings"); - unsigned nr, nc; - if( nrow_t==0 ){ - nr=nc=getNumberOfNodeTypes(); - } else{ - nr=nrow_t; nc = getNumberOfNodeTypes() - nr; + if( multiple ) error("keyword " + key + " does not work with multiple input strings"); + unsigned nr, nc; + if( nrow_t==0 ) { + nr=nc=getNumberOfNodeTypes(); + } else { + nr=nrow_t; nc = getNumberOfNodeTypes() - nr; + } + for(unsigned i=0; i<nr; ++i) { + // Retrieve the base number + unsigned ibase; + if( nc<10 ) { + ibase=(i+1)*10; + } else if ( nc<100 ) { + ibase=(i+1)*100; + } else { + error("wow this is an error I never would have expected"); } - for(unsigned i=0;i<nr;++i){ - // Retrieve the base number - unsigned ibase; - if( nc<10 ){ - ibase=(i+1)*10; - } else if ( nc<100 ){ - ibase=(i+1)*100; - } else { - error("wow this is an error I never would have expected"); - } - - for(unsigned j=i;j<nc;++j){ - std::vector<std::string> sw(1); parseNumbered(key,ibase+j+1,sw[0]); - if(sw[0].length()==0){ - std::string num; Tools::convert(ibase+j+1,num); - error("could not find " + key + num + " keyword. Need one " + key + " keyword for each distinct base-multicolvar-pair type"); - } - setupConnector( connect_id, i, j, sw ); - } + + for(unsigned j=i; j<nc; ++j) { + std::vector<std::string> sw(1); parseNumbered(key,ibase+j+1,sw[0]); + if(sw[0].length()==0) { + std::string num; Tools::convert(ibase+j+1,num); + error("could not find " + key + num + " keyword. Need one " + key + " keyword for each distinct base-multicolvar-pair type"); + } + setupConnector( connect_id, i, j, sw ); } + } } connect_id++; } unsigned AdjacencyMatrixBase::getSizeOfInputVectors() const { - if( mybasemulticolvars.size()==0 ) return 2; + if( mybasemulticolvars.size()==0 ) return 2; unsigned nq = mybasemulticolvars[0]->getNumberOfQuantities(); - for(unsigned i=1;i<mybasemulticolvars.size();++i){ - if( mybasemulticolvars[i]->getNumberOfQuantities()!=nq ) error("mismatch between vectors in base colvars"); + for(unsigned i=1; i<mybasemulticolvars.size(); ++i) { + if( mybasemulticolvars[i]->getNumberOfQuantities()!=nq ) error("mismatch between vectors in base colvars"); } return nq; } @@ -108,69 +108,69 @@ unsigned AdjacencyMatrixBase::getNumberOfNodeTypes() const { void AdjacencyMatrixBase::retrieveTypeDimensions( unsigned& nrows, unsigned& ncols, unsigned& ntype ) const { bool allsame=(ablocks[0].size()==ablocks[1].size()); - if( allsame ){ - for(unsigned i=0;i<ablocks[0].size();++i){ - if( ablocks[0][i]!=ablocks[1][i] ) allsame=false; - } - } - - if( allsame ){ - std::vector<unsigned> types(1); types[0]=atom_lab[ablocks[0][0]].first; - for(unsigned i=1;i<ablocks[0].size();++i){ - bool found = false; - for(unsigned j=0;j<types.size();++j){ - if( atom_lab[ablocks[0][i]].first==types[j] ){ found=true; break; } - } - if( !found ) types.push_back( atom_lab[ablocks[0][i]].first ); + if( allsame ) { + for(unsigned i=0; i<ablocks[0].size(); ++i) { + if( ablocks[0][i]!=ablocks[1][i] ) allsame=false; + } + } + + if( allsame ) { + std::vector<unsigned> types(1); types[0]=atom_lab[ablocks[0][0]].first; + for(unsigned i=1; i<ablocks[0].size(); ++i) { + bool found = false; + for(unsigned j=0; j<types.size(); ++j) { + if( atom_lab[ablocks[0][i]].first==types[j] ) { found=true; break; } } - ntype=0; nrows=ncols=types.size(); + if( !found ) types.push_back( atom_lab[ablocks[0][i]].first ); + } + ntype=0; nrows=ncols=types.size(); } else { - std::vector<unsigned> types(1); types[0]=atom_lab[ablocks[0][0]].first; - for(unsigned i=1;i<ablocks[0].size();++i){ - bool found = false; - for(unsigned j=0;j<types.size();++j){ - if( atom_lab[ablocks[0][i]].first==types[j] ){ found=true; break; } - } - if( !found ) types.push_back( atom_lab[ablocks[0][i]].first ); + std::vector<unsigned> types(1); types[0]=atom_lab[ablocks[0][0]].first; + for(unsigned i=1; i<ablocks[0].size(); ++i) { + bool found = false; + for(unsigned j=0; j<types.size(); ++j) { + if( atom_lab[ablocks[0][i]].first==types[j] ) { found=true; break; } } - nrows=ntype=types.size(); - for(unsigned i=0;i<ablocks[1].size();++i){ - bool found = false; - for(unsigned j=0;j<types.size();++j){ - if( atom_lab[ablocks[1][i]].first==types[j] ){ found=true; break; } - } - if( !found ) types.push_back( atom_lab[ablocks[1][i]].first ); + if( !found ) types.push_back( atom_lab[ablocks[0][i]].first ); + } + nrows=ntype=types.size(); + for(unsigned i=0; i<ablocks[1].size(); ++i) { + bool found = false; + for(unsigned j=0; j<types.size(); ++j) { + if( atom_lab[ablocks[1][i]].first==types[j] ) { found=true; break; } } - if( types.size()==nrows ){ ntype=0; ncols=1; plumed_assert( types.size()==1 && atom_lab[ablocks[0][0]].first==0 ); } - else ncols = types.size() - ntype; + if( !found ) types.push_back( atom_lab[ablocks[1][i]].first ); + } + if( types.size()==nrows ) { ntype=0; ncols=1; plumed_assert( types.size()==1 && atom_lab[ablocks[0][0]].first==0 ); } + else ncols = types.size() - ntype; } } -void AdjacencyMatrixBase::finishMatrixSetup( const bool& symmetric, const std::vector<AtomNumber>& all_atoms ){ +void AdjacencyMatrixBase::finishMatrixSetup( const bool& symmetric, const std::vector<AtomNumber>& all_atoms ) { std::string param; if( symmetric && ablocks[0].size()==ablocks[1].size() ) param="SYMMETRIC"; - if( !symmetric ){ - bool usehbonds=( ablocks[0].size()==ablocks[1].size() ); - if( usehbonds ){ - for(unsigned i=0;i<ablocks[0].size();++i){ - if( ablocks[0][i]!=ablocks[1][i] ){ usehbonds = false; break; } - } - if( usehbonds ) param="HBONDS"; - } + if( !symmetric ) { + bool usehbonds=( ablocks[0].size()==ablocks[1].size() ); + if( usehbonds ) { + for(unsigned i=0; i<ablocks[0].size(); ++i) { + if( ablocks[0][i]!=ablocks[1][i] ) { usehbonds = false; break; } + } + if( usehbonds ) param="HBONDS"; + } } vesselbase::VesselOptions da("","",0,param,this); Keywords keys; AdjacencyMatrixVessel::registerKeywords( keys ); vesselbase::VesselOptions da2(da,keys); mat = new AdjacencyMatrixVessel(da2); addVessel( mat ); - setupMultiColvarBase( all_atoms ); + setupMultiColvarBase( all_atoms ); } -void AdjacencyMatrixBase::readMaxTwoSpeciesMatrix( const std::string& key0, const std::string& key1, const std::string& key2, const bool& symmetric ){ +void AdjacencyMatrixBase::readMaxTwoSpeciesMatrix( const std::string& key0, const std::string& key1, const std::string& key2, const bool& symmetric ) { std::vector<AtomNumber> all_atoms; readTwoGroups( key0, key1, key2, all_atoms ); finishMatrixSetup( symmetric, all_atoms ); } -void AdjacencyMatrixBase::readMaxThreeSpeciesMatrix( const std::string& key0, const std::string& key1, const std::string& key2, const std::string& keym, const bool& symmetric ){ +void AdjacencyMatrixBase::readMaxThreeSpeciesMatrix( const std::string& key0, const std::string& key1, const std::string& key2, const std::string& keym, const bool& symmetric ) { std::vector<AtomNumber> all_atoms; readGroupKeywords( key0, key1, key2, keym, true, symmetric, all_atoms ); finishMatrixSetup( symmetric, all_atoms ); } @@ -180,14 +180,14 @@ void AdjacencyMatrixBase::readMaxThreeSpeciesMatrix( const std::string& key0, co // AtomNumber AdjacencyMatrixBase::getAbsoluteIndexOfCentralAtom(const unsigned& i) const { // plumed_dbg_assert( i<myinputdata.getFullNumberOfBaseTasks() ); // return myinputdata.getAtomicIndex( i ); -// } +// } -void AdjacencyMatrixBase::recalculateMatrixElement( const unsigned& myelem, MultiValue& myvals ){ +void AdjacencyMatrixBase::recalculateMatrixElement( const unsigned& myelem, MultiValue& myvals ) { std::vector<unsigned> myatoms; decodeIndexToAtoms( getTaskCode( myelem ), myatoms ); unsigned i=myatoms[0], j=myatoms[1]; - for(unsigned k=bookeeping(i,j).first;k<bookeeping(i,j).second;++k){ - if( !taskIsCurrentlyActive(k) ) continue; - performTask( k, getTaskCode(k), myvals ); // This may not accumulate as we would like GAT + for(unsigned k=bookeeping(i,j).first; k<bookeeping(i,j).second; ++k) { + if( !taskIsCurrentlyActive(k) ) continue; + performTask( k, getTaskCode(k), myvals ); // This may not accumulate as we would like GAT } } diff --git a/src/adjmat/AdjacencyMatrixBase.h b/src/adjmat/AdjacencyMatrixBase.h index 1e308baea..c9b44d245 100644 --- a/src/adjmat/AdjacencyMatrixBase.h +++ b/src/adjmat/AdjacencyMatrixBase.h @@ -29,10 +29,10 @@ namespace PLMD { namespace adjmat { class AdjacencyMatrixBase : public multicolvar::MultiColvarBase { -friend class AdjacencyMatrixVessel; -friend class ActionWithInputMatrix; -friend class MatrixColumnSums; -friend class MatrixRowSums; + friend class AdjacencyMatrixVessel; + friend class ActionWithInputMatrix; + friend class MatrixColumnSums; + friend class MatrixRowSums; private: /// Used for read in of multiple connection descriptors unsigned connect_id; @@ -73,28 +73,28 @@ public: /// Create the connection object virtual void setupConnector( const unsigned& id, const unsigned& i, const unsigned& j, const std::vector<std::string>& desc ) = 0; /// None of these things are allowed - bool isPeriodic(){ return false; } - Vector getCentralAtom(){ plumed_merror("cannot find central atoms for adjacency matrix actions"); Vector dum; return dum; } + bool isPeriodic() { return false; } + Vector getCentralAtom() { plumed_merror("cannot find central atoms for adjacency matrix actions"); Vector dum; return dum; } /// Get the atom number - AtomNumber getAbsoluteIndexOfCentralAtom( const unsigned& i ) const ; + AtomNumber getAbsoluteIndexOfCentralAtom( const unsigned& i ) const ; }; inline -AdjacencyMatrixVessel* AdjacencyMatrixBase::getAdjacencyVessel(){ +AdjacencyMatrixVessel* AdjacencyMatrixBase::getAdjacencyVessel() { return mat; } inline unsigned AdjacencyMatrixBase::getBaseColvarNumber( const unsigned& inum ) const { - if( atom_lab[inum].first>0 ) return atom_lab[inum].first-1; + if( atom_lab[inum].first>0 ) return atom_lab[inum].first-1; return 0; } inline AtomNumber AdjacencyMatrixBase::getAbsoluteIndexOfCentralAtom( const unsigned& iatom ) const { - if( atom_lab[iatom].first>0 ){ - unsigned mmc=atom_lab[ iatom ].first - 1; - return mybasemulticolvars[mmc]->getAbsoluteIndexOfCentralAtom( atom_lab[iatom].second ); + if( atom_lab[iatom].first>0 ) { + unsigned mmc=atom_lab[ iatom ].first - 1; + return mybasemulticolvars[mmc]->getAbsoluteIndexOfCentralAtom( atom_lab[iatom].second ); } return ActionAtomistic::getAbsoluteIndex( atom_lab[iatom].second ); } diff --git a/src/adjmat/AdjacencyMatrixVessel.cpp b/src/adjmat/AdjacencyMatrixVessel.cpp index 6d07fc40e..f4a62bb6d 100644 --- a/src/adjmat/AdjacencyMatrixVessel.cpp +++ b/src/adjmat/AdjacencyMatrixVessel.cpp @@ -20,20 +20,20 @@ along with plumed. If not, see <http://www.gnu.org/licenses/>. +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ #include "AdjacencyMatrixVessel.h" -#include "AdjacencyMatrixBase.h" +#include "AdjacencyMatrixBase.h" #include "vesselbase/ActionWithVessel.h" namespace PLMD { namespace adjmat { -void AdjacencyMatrixVessel::registerKeywords( Keywords& keys ){ +void AdjacencyMatrixVessel::registerKeywords( Keywords& keys ) { StoreDataVessel::registerKeywords(keys); keys.addFlag("SYMMETRIC",false,"is the matrix symmetric"); keys.addFlag("HBONDS",false,"can we think of the matrix as a undirected graph"); } AdjacencyMatrixVessel::AdjacencyMatrixVessel( const vesselbase::VesselOptions& da ): -StoreDataVessel(da) + StoreDataVessel(da) { function=dynamic_cast<AdjacencyMatrixBase*>( getAction() ); plumed_assert( function ); @@ -65,13 +65,13 @@ bool AdjacencyMatrixVessel::matrixElementIsActive( const unsigned& ielem, const unsigned AdjacencyMatrixVessel::getStoreIndexFromMatrixIndices( const unsigned& ielem, const unsigned& jelem ) const { if( !symmetric && !hbonds ) return (function->ablocks[1].size())*ielem + jelem; - if( !symmetric ){ - plumed_dbg_assert( ielem!=jelem ); - if( jelem<ielem ) return (function->ablocks[1].size()-1)*ielem + jelem; - return (function->ablocks[1].size()-1)*ielem + jelem - 1; + if( !symmetric ) { + plumed_dbg_assert( ielem!=jelem ); + if( jelem<ielem ) return (function->ablocks[1].size()-1)*ielem + jelem; + return (function->ablocks[1].size()-1)*ielem + jelem - 1; } if( ielem>jelem ) return 0.5*ielem*(ielem-1)+jelem; - return 0.5*jelem*(jelem-1) + ielem; + return 0.5*jelem*(jelem-1) + ielem; } AdjacencyMatrixBase* AdjacencyMatrixVessel::getMatrixAction() { @@ -79,61 +79,61 @@ AdjacencyMatrixBase* AdjacencyMatrixVessel::getMatrixAction() { } void AdjacencyMatrixVessel::getMatrixIndices( const unsigned& code, unsigned& i, unsigned& j ) const { - std::vector<unsigned> myatoms; function->decodeIndexToAtoms( function->getTaskCode(code), myatoms ); - i=myatoms[0]; j=myatoms[1]; - if( !undirectedGraph() ) j -= function->ablocks[0].size(); // Have to remove number of columns as returns number in ablocks[1] + std::vector<unsigned> myatoms; function->decodeIndexToAtoms( function->getTaskCode(code), myatoms ); + i=myatoms[0]; j=myatoms[1]; + if( !undirectedGraph() ) j -= function->ablocks[0].size(); // Have to remove number of columns as returns number in ablocks[1] } -void AdjacencyMatrixVessel::retrieveMatrix( DynamicList<unsigned>& myactive_elements, Matrix<double>& mymatrix ){ +void AdjacencyMatrixVessel::retrieveMatrix( DynamicList<unsigned>& myactive_elements, Matrix<double>& mymatrix ) { unsigned vin; double df; - myactive_elements.deactivateAll(); std::vector<double> vals( getNumberOfComponents() ); - for(unsigned i=0;i<getNumberOfStoredValues();++i){ - retrieveSequentialValue( i, false, vals ); - if( vals[0]<epsilon ) continue ; + myactive_elements.deactivateAll(); std::vector<double> vals( getNumberOfComponents() ); + for(unsigned i=0; i<getNumberOfStoredValues(); ++i) { + retrieveSequentialValue( i, false, vals ); + if( vals[0]<epsilon ) continue ; - myactive_elements.activate(i); - unsigned j, k; getMatrixIndices( function->getPositionInFullTaskList(i), k, j ); + myactive_elements.activate(i); + unsigned j, k; getMatrixIndices( function->getPositionInFullTaskList(i), k, j ); - if( symmetric ) mymatrix(k,j)=mymatrix(j,k)=vals[0]*vals[1]; - else mymatrix(k,j)=vals[0]*vals[1]; + if( symmetric ) mymatrix(k,j)=mymatrix(j,k)=vals[0]*vals[1]; + else mymatrix(k,j)=vals[0]*vals[1]; } - myactive_elements.updateActiveMembers(); + myactive_elements.updateActiveMembers(); } -void AdjacencyMatrixVessel::retrieveAdjacencyLists( std::vector<unsigned>& nneigh, Matrix<unsigned>& adj_list ){ +void AdjacencyMatrixVessel::retrieveAdjacencyLists( std::vector<unsigned>& nneigh, Matrix<unsigned>& adj_list ) { plumed_dbg_assert( undirectedGraph() ); // Currently everything has zero neighbors - for(unsigned i=0;i<nneigh.size();++i) nneigh[i]=0; + for(unsigned i=0; i<nneigh.size(); ++i) nneigh[i]=0; // And set up the adjacency list std::vector<double> myvals( getNumberOfComponents() ); - for(unsigned i=0;i<getNumberOfStoredValues();++i){ - // Check if atoms are connected - retrieveSequentialValue( i, false, myvals ); - if( myvals[0]<epsilon || myvals[1]<epsilon ) continue ; - - unsigned j, k; getMatrixIndices( function->getPositionInFullTaskList(i), k, j ); - - if( nneigh[j]>=adj_list.ncols() || nneigh[k]>=adj_list.ncols() ) error("adjacency lists are not large enough, increase maxconnections"); - // Store if atoms are connected - // unsigned j, k; getMatrixIndices( i, k, j ); - adj_list(k,nneigh[k])=j; nneigh[k]++; - adj_list(j,nneigh[j])=k; nneigh[j]++; + for(unsigned i=0; i<getNumberOfStoredValues(); ++i) { + // Check if atoms are connected + retrieveSequentialValue( i, false, myvals ); + if( myvals[0]<epsilon || myvals[1]<epsilon ) continue ; + + unsigned j, k; getMatrixIndices( function->getPositionInFullTaskList(i), k, j ); + + if( nneigh[j]>=adj_list.ncols() || nneigh[k]>=adj_list.ncols() ) error("adjacency lists are not large enough, increase maxconnections"); + // Store if atoms are connected + // unsigned j, k; getMatrixIndices( i, k, j ); + adj_list(k,nneigh[k])=j; nneigh[k]++; + adj_list(j,nneigh[j])=k; nneigh[j]++; } } -void AdjacencyMatrixVessel::retrieveEdgeList( unsigned& nedge, std::vector<std::pair<unsigned,unsigned> >& edge_list ){ +void AdjacencyMatrixVessel::retrieveEdgeList( unsigned& nedge, std::vector<std::pair<unsigned,unsigned> >& edge_list ) { plumed_dbg_assert( undirectedGraph() ); nedge=0; std::vector<double> myvals( getNumberOfComponents() ); if( getNumberOfStoredValues()>edge_list.size() ) error("adjacency lists are not large enough, increase maxconnections"); - for(unsigned i=0;i<getNumberOfStoredValues();++i){ - // Check if atoms are connected - retrieveSequentialValue( i, false, myvals ); - if( myvals[0]<epsilon || myvals[1]<epsilon ) continue ; + for(unsigned i=0; i<getNumberOfStoredValues(); ++i) { + // Check if atoms are connected + retrieveSequentialValue( i, false, myvals ); + if( myvals[0]<epsilon || myvals[1]<epsilon ) continue ; - getMatrixIndices( function->getPositionInFullTaskList(i), edge_list[nedge].first, edge_list[nedge].second ); - nedge++; + getMatrixIndices( function->getPositionInFullTaskList(i), edge_list[nedge].first, edge_list[nedge].second ); + nedge++; } } @@ -141,7 +141,7 @@ bool AdjacencyMatrixVessel::nodesAreConnected( const unsigned& iatom, const unsi if( !matrixElementIsActive( iatom, jatom ) ) return false; unsigned ind=getStoreIndexFromMatrixIndices( iatom, jatom ); - std::vector<double> myvals( getNumberOfComponents() ); + std::vector<double> myvals( getNumberOfComponents() ); retrieveValueWithIndex( ind, false, myvals ); return ( myvals[0]>epsilon && myvals[1]>epsilon ); } diff --git a/src/adjmat/AdjacencyMatrixVessel.h b/src/adjmat/AdjacencyMatrixVessel.h index 637208bd4..7e1ef1586 100644 --- a/src/adjmat/AdjacencyMatrixVessel.h +++ b/src/adjmat/AdjacencyMatrixVessel.h @@ -22,7 +22,7 @@ #ifndef __PLUMED_adjmat_AdjacencyMatrixVessel_h #define __PLUMED_adjmat_AdjacencyMatrixVessel_h -#include "vesselbase/StoreDataVessel.h" +#include "vesselbase/StoreDataVessel.h" #include "multicolvar/MultiColvarBase.h" namespace PLMD { @@ -30,15 +30,15 @@ namespace adjmat { class AdjacencyMatrixBase; -// One school of thought would have it that it makes more sense to +// One school of thought would have it that it makes more sense to // have the functionality contained within this class in AdjacencyMatrixBase // I have not done this as I can inherit many useful things from StoreDataVessel // If I put this functionality within AdjacencyMatrixBase I would have to reimplement // these features. class AdjacencyMatrixVessel : public vesselbase::StoreDataVessel { -friend class AdjacencyMatrixBase; -friend class ActionWithInputMatrix; + friend class AdjacencyMatrixBase; + friend class ActionWithInputMatrix; private: /// Pointer to underlying action AdjacencyMatrixBase* function; @@ -63,7 +63,7 @@ public: /// void getMatrixIndices( const unsigned& code, unsigned& i, unsigned& j ) const ; /// Can we think of the matrix as an undirected graph - bool undirectedGraph() const ; + bool undirectedGraph() const ; /// Is the matrix symmetric bool isSymmetric() const ; /// Get the number of rows diff --git a/src/adjmat/AlignedMatrixBase.cpp b/src/adjmat/AlignedMatrixBase.cpp index 28fd47c93..408cf8c73 100644 --- a/src/adjmat/AlignedMatrixBase.cpp +++ b/src/adjmat/AlignedMatrixBase.cpp @@ -27,59 +27,59 @@ namespace PLMD { namespace adjmat { -void AlignedMatrixBase::registerKeywords( Keywords& keys ){ +void AlignedMatrixBase::registerKeywords( Keywords& keys ) { AdjacencyMatrixBase::registerKeywords( keys ); keys.add("atoms","ATOMS","The list of molecules for which you would like to calculate the contact matrix. The molecules involved must " - "have an orientation so your list will be a list of the labels of \\ref mcolv or \\ref multicolvarfunction " - "as PLUMED calculates the orientations of molecules within these operations. Please note also that the majority " - "of \\ref mcolv and \\ref multicolvarfunction do not calculate a molecular orientation."); + "have an orientation so your list will be a list of the labels of \\ref mcolv or \\ref multicolvarfunction " + "as PLUMED calculates the orientations of molecules within these operations. Please note also that the majority " + "of \\ref mcolv and \\ref multicolvarfunction do not calculate a molecular orientation."); keys.add("atoms-1","ATOMSA","The list of molecules that you would like to use for the rows of the contact matrix. The molecules involved must " - "have an orientation so your list will be a list of the labels of \\ref mcolv or \\ref multicolvarfunction " - "as PLUMED calculates the orientations of molecules within these operations. Please note also that the majority " - "of \\ref mcolv and \\ref multicolvarfunction do not calculate a molecular orientation."); + "have an orientation so your list will be a list of the labels of \\ref mcolv or \\ref multicolvarfunction " + "as PLUMED calculates the orientations of molecules within these operations. Please note also that the majority " + "of \\ref mcolv and \\ref multicolvarfunction do not calculate a molecular orientation."); keys.add("atoms-1","ATOMSB","The list of molecules that you would like to use for the columns of the contact matrix. The molecules involved must " - "have an orientation so your list will be a list of the labels of \\ref mcolv or \\ref multicolvarfunction " - "as PLUMED calculates the orientations of molecules within these operations. Please note also that the majority " - "of \\ref mcolv and \\ref multicolvarfunction do not calculate a molecular orientation."); + "have an orientation so your list will be a list of the labels of \\ref mcolv or \\ref multicolvarfunction " + "as PLUMED calculates the orientations of molecules within these operations. Please note also that the majority " + "of \\ref mcolv and \\ref multicolvarfunction do not calculate a molecular orientation."); keys.add("numbered","SWITCH","This keyword is used if you want to employ an alternative to the continuous swiching function defined above. " - "The following provides information on the \\ref switchingfunction that are available. " - "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); + "The following provides information on the \\ref switchingfunction that are available. " + "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); } AlignedMatrixBase::AlignedMatrixBase( const ActionOptions& ao ): -Action(ao), -AdjacencyMatrixBase(ao) + Action(ao), + AdjacencyMatrixBase(ao) { // Read in the atomic positions readMaxTwoSpeciesMatrix( "ATOMS", "ATOMSA", "ATOMSB", true ); - unsigned nrows, ncols; retrieveTypeDimensions( nrows, ncols, ncol_t ); + unsigned nrows, ncols; retrieveTypeDimensions( nrows, ncols, ncol_t ); if( mybasemulticolvars.size()==0 ) error("cannot use atom indices as input to this variable / input was not specified"); if( getSizeOfInputVectors()<3 ) error("base multicolvars do not calculate an orientation"); // Read in the switching function switchingFunction.resize( nrows, ncols ); - parseConnectionDescriptions("SWITCH",false,ncol_t); + parseConnectionDescriptions("SWITCH",false,ncol_t); // Find the largest sf cutoff double sfmax=switchingFunction(0,0).get_dmax(); - for(unsigned i=0;i<getNumberOfNodeTypes();++i){ - for(unsigned j=0;j<getNumberOfNodeTypes();++j){ - double tsf=switchingFunction(i,j).get_dmax(); - if( tsf>sfmax ) sfmax=tsf; - } + for(unsigned i=0; i<getNumberOfNodeTypes(); ++i) { + for(unsigned j=0; j<getNumberOfNodeTypes(); ++j) { + double tsf=switchingFunction(i,j).get_dmax(); + if( tsf>sfmax ) sfmax=tsf; + } } // And set the link cell cutoff setLinkCellCutoff( sfmax ); } -void AlignedMatrixBase::setupConnector( const unsigned& id, const unsigned& i, const unsigned& j, const std::vector<std::string>& desc ){ - plumed_assert( id<2 ); - if( id==0 ){ - plumed_assert( desc.size()==1 ); std::string errors; switchingFunction(j,i).set(desc[0],errors); - if( errors.length()!=0 ) error("problem reading switching function in SWITCH keywrd description " + errors); - if( j!=i) switchingFunction(i,j).set(desc[0],errors); - log.printf(" %u th and %u th multicolvar groups must be within %s\n",i+1,j+1,(switchingFunction(i,j).description()).c_str() ); - } else if( id==1 ){ - readOrientationConnector( i, j, desc ); +void AlignedMatrixBase::setupConnector( const unsigned& id, const unsigned& i, const unsigned& j, const std::vector<std::string>& desc ) { + plumed_assert( id<2 ); + if( id==0 ) { + plumed_assert( desc.size()==1 ); std::string errors; switchingFunction(j,i).set(desc[0],errors); + if( errors.length()!=0 ) error("problem reading switching function in SWITCH keywrd description " + errors); + if( j!=i) switchingFunction(i,j).set(desc[0],errors); + log.printf(" %u th and %u th multicolvar groups must be within %s\n",i+1,j+1,(switchingFunction(i,j).description()).c_str() ); + } else if( id==1 ) { + readOrientationConnector( i, j, desc ); } } @@ -94,21 +94,21 @@ double AlignedMatrixBase::compute( const unsigned& tindex, multicolvar::AtomValu std::vector<double> orient0(ncomp), orient1(ncomp), dorient0(ncomp), dorient1(ncomp); Vector distance = getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); getInputData( 0, true, myatoms, orient0 ); getInputData( 1, true, myatoms, orient1 ); - double f_dot = computeVectorFunction( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) )-ncol_t, + double f_dot = computeVectorFunction( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) )-ncol_t, distance, orient0, orient1, ddistance, dorient0, dorient1 ); // Retrieve the weight of the connection - double dfunc, sw = switchingFunction( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) )-ncol_t ).calculate( distance.modulo(), dfunc ); + double dfunc, sw = switchingFunction( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) )-ncol_t ).calculate( distance.modulo(), dfunc ); - if( !doNotCalculateDerivatives() ){ - addAtomDerivatives( 1, 0, (-dfunc)*f_dot*distance - sw*ddistance, myatoms ); - addAtomDerivatives( 1, 1, (+dfunc)*f_dot*distance + sw*ddistance, myatoms ); - myatoms.addBoxDerivatives( 1, (-dfunc)*f_dot*Tensor(distance,distance) - sw*extProduct( distance, ddistance ) ); + if( !doNotCalculateDerivatives() ) { + addAtomDerivatives( 1, 0, (-dfunc)*f_dot*distance - sw*ddistance, myatoms ); + addAtomDerivatives( 1, 1, (+dfunc)*f_dot*distance + sw*ddistance, myatoms ); + myatoms.addBoxDerivatives( 1, (-dfunc)*f_dot*Tensor(distance,distance) - sw*extProduct( distance, ddistance ) ); - // Add derivatives of orientation - for(unsigned k=2;k<orient0.size();++k){ dorient0[k]*=sw; dorient1[k]*=sw; } - mergeInputDerivatives( 1, 2, orient0.size(), 0, dorient0, getInputDerivatives( 0, true, myatoms ), myatoms ); - mergeInputDerivatives( 1, 2, orient1.size(), 1, dorient1, getInputDerivatives( 1, true, myatoms ), myatoms ); + // Add derivatives of orientation + for(unsigned k=2; k<orient0.size(); ++k) { dorient0[k]*=sw; dorient1[k]*=sw; } + mergeInputDerivatives( 1, 2, orient0.size(), 0, dorient0, getInputDerivatives( 0, true, myatoms ), myatoms ); + mergeInputDerivatives( 1, 2, orient1.size(), 1, dorient1, getInputDerivatives( 1, true, myatoms ), myatoms ); } return sw*f_dot; } diff --git a/src/adjmat/ClusterAnalysisBase.cpp b/src/adjmat/ClusterAnalysisBase.cpp index 390cadc06..ee6c74306 100644 --- a/src/adjmat/ClusterAnalysisBase.cpp +++ b/src/adjmat/ClusterAnalysisBase.cpp @@ -24,17 +24,17 @@ namespace PLMD { namespace adjmat { -void ClusterAnalysisBase::registerKeywords( Keywords& keys ){ +void ClusterAnalysisBase::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); keys.add("compulsory","CLUSTERS","the label of the action that does the clustering"); } ClusterAnalysisBase::ClusterAnalysisBase(const ActionOptions& ao): -Action(ao), -MultiColvarBase(ao), -myfvals(0,0), -myfatoms( myfvals, this ), -myclusters(NULL) + Action(ao), + MultiColvarBase(ao), + myfvals(0,0), + myfatoms( myfvals, this ), + myclusters(NULL) { // This makes these colvars behave appropriately with dump and analysis matsums=usespecies=true; std::vector<AtomNumber> fake_atoms; @@ -46,14 +46,14 @@ myclusters(NULL) // Setup the atom pack myfatoms.setNumberOfAtoms( myclusters->getNumberOfNodes() ); myfvals.getIndices().resize( myclusters->getNumberOfNodes() ); - for(unsigned i=0;i<myclusters->getNumberOfNodes();++i) myfatoms.setAtomIndex( i, i ); + for(unsigned i=0; i<myclusters->getNumberOfNodes(); ++i) myfatoms.setAtomIndex( i, i ); } -void ClusterAnalysisBase::turnOnDerivatives(){ +void ClusterAnalysisBase::turnOnDerivatives() { // Check for dubious vessels - for(unsigned i=0;i<getNumberOfVessels();++i){ - if( getPntrToVessel(i)->getName()=="MEAN" ) error("MEAN of cluster is not differentiable"); - if( getPntrToVessel(i)->getName()=="VMEAN" ) error("VMEAN of cluster is not differentiable"); + for(unsigned i=0; i<getNumberOfVessels(); ++i) { + if( getPntrToVessel(i)->getName()=="MEAN" ) error("MEAN of cluster is not differentiable"); + if( getPntrToVessel(i)->getName()=="VMEAN" ) error("VMEAN of cluster is not differentiable"); } MultiColvarBase::turnOnDerivatives(); } @@ -70,7 +70,7 @@ unsigned ClusterAnalysisBase::getNumberOfClusters() const { return myclusters->getNumberOfClusters(); } -bool ClusterAnalysisBase::isPeriodic(){ +bool ClusterAnalysisBase::isPeriodic() { return mybasemulticolvars[0]->isPeriodic(); } diff --git a/src/adjmat/ClusterAnalysisBase.h b/src/adjmat/ClusterAnalysisBase.h index 58d4b91e7..24a1b80ae 100644 --- a/src/adjmat/ClusterAnalysisBase.h +++ b/src/adjmat/ClusterAnalysisBase.h @@ -48,7 +48,7 @@ public: unsigned getNumberOfQuantities() const ; bool isPeriodic(); void turnOnDerivatives(); - void setupActiveTaskSet( std::vector<unsigned>& active_tasks, const std::string& input_label ){} + void setupActiveTaskSet( std::vector<unsigned>& active_tasks, const std::string& input_label ) {} Vector getPositionOfAtomForLinkCells( const unsigned& ) const ; double compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ) const { plumed_error(); } }; diff --git a/src/adjmat/ClusterDiameter.cpp b/src/adjmat/ClusterDiameter.cpp index c1a6fa54a..ec26f2eeb 100644 --- a/src/adjmat/ClusterDiameter.cpp +++ b/src/adjmat/ClusterDiameter.cpp @@ -26,11 +26,11 @@ /* Print out the diameter of one of the connected components -As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the -so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether +As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the +so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether or not the \f$i\f$th and \f$j\f$th atoms/molecules from a set of \f$N\f$ atoms/molecules are adjacent or not. When analysing these matrix we can treat them as a graph and find connected components using some clustering algorithm. This action is used in tandem with this form of analysis -to output the largest of the distances between the paris of atoms that are connected together in a particular connected component. It is important to +to output the largest of the distances between the paris of atoms that are connected together in a particular connected component. It is important to note that the quantity that is output by this action is not differentiable. As such it cannot be used as a collective variable in a biased simulation. \par Examples @@ -79,51 +79,51 @@ public: PLUMED_REGISTER_ACTION(ClusterDiameter,"CLUSTER_DIAMETER") -void ClusterDiameter::registerKeywords( Keywords& keys ){ +void ClusterDiameter::registerKeywords( Keywords& keys ) { ClusterAnalysisBase::registerKeywords( keys ); keys.add("compulsory","CLUSTER","1","which cluster would you like to look at 1 is the largest cluster, 2 is the second largest, 3 is the the third largest and so on."); } ClusterDiameter::ClusterDiameter(const ActionOptions&ao): -Action(ao), -ClusterAnalysisBase(ao) + Action(ao), + ClusterAnalysisBase(ao) { - // Find out which cluster we want - parse("CLUSTER",clustr); - - if( clustr<1 ) error("cannot look for a cluster larger than the largest cluster"); - if( clustr>getNumberOfNodes() ) error("cluster selected is invalid - too few atoms in system"); - - // Create the task list - for(unsigned i=0;i<getNumberOfNodes();++i){ - for(unsigned j=0;j<getNumberOfNodes();++j) addTaskToList( i*getNumberOfNodes() + j ); - } - // Now create a higest vessel - addVessel("HIGHEST", "", -1); std::vector<AtomNumber> fake_atoms; setupMultiColvarBase( fake_atoms ); + // Find out which cluster we want + parse("CLUSTER",clustr); + + if( clustr<1 ) error("cannot look for a cluster larger than the largest cluster"); + if( clustr>getNumberOfNodes() ) error("cluster selected is invalid - too few atoms in system"); + + // Create the task list + for(unsigned i=0; i<getNumberOfNodes(); ++i) { + for(unsigned j=0; j<getNumberOfNodes(); ++j) addTaskToList( i*getNumberOfNodes() + j ); + } + // Now create a higest vessel + addVessel("HIGHEST", "", -1); std::vector<AtomNumber> fake_atoms; setupMultiColvarBase( fake_atoms ); } -void ClusterDiameter::turnOnDerivatives(){ - error("cannot calculate derivatives of cluster radius. This quantity is not differentiable"); +void ClusterDiameter::turnOnDerivatives() { + error("cannot calculate derivatives of cluster radius. This quantity is not differentiable"); } -void ClusterDiameter::calculate(){ - // Retrieve the atoms in the largest cluster - std::vector<unsigned> myatoms; retrieveAtomsInCluster( clustr, myatoms ); - // Activate the relevant tasks - deactivateAllTasks(); - for(unsigned i=1;i<myatoms.size();++i){ - for(unsigned j=0;j<i;++j) taskFlags[ myatoms[i]*getNumberOfNodes() + myatoms[j] ] = 1; - } - lockContributors(); - // Now do the calculation - runAllTasks(); +void ClusterDiameter::calculate() { + // Retrieve the atoms in the largest cluster + std::vector<unsigned> myatoms; retrieveAtomsInCluster( clustr, myatoms ); + // Activate the relevant tasks + deactivateAllTasks(); + for(unsigned i=1; i<myatoms.size(); ++i) { + for(unsigned j=0; j<i; ++j) taskFlags[ myatoms[i]*getNumberOfNodes() + myatoms[j] ] = 1; + } + lockContributors(); + // Now do the calculation + runAllTasks(); } -void ClusterDiameter::performTask( const unsigned& task_index, const unsigned& current, MultiValue& myvals ) const { +void ClusterDiameter::performTask( const unsigned& task_index, const unsigned& current, MultiValue& myvals ) const { unsigned iatom=std::floor(current/getNumberOfNodes()), jatom = current - iatom*getNumberOfNodes(); Vector distance=getSeparation( getPosition(iatom), getPosition(jatom) ); double dd = distance.modulo(); - myvals.setValue( 0, 1.0 ); myvals.setValue( 1, dd ); + myvals.setValue( 0, 1.0 ); myvals.setValue( 1, dd ); } } diff --git a/src/adjmat/ClusterDistribution.cpp b/src/adjmat/ClusterDistribution.cpp index 93039bc5d..93f12fb04 100644 --- a/src/adjmat/ClusterDistribution.cpp +++ b/src/adjmat/ClusterDistribution.cpp @@ -28,18 +28,18 @@ /* Calculate functions of the distribution of properties in your connected components. -This collective variable was developed for looking at nucleation phenomena, where you are -interested in using studying the behavior of atoms in small aggregates or nuclei. In these sorts of -problems you might be interested in the distribution of the sizes of the clusters in your system. +This collective variable was developed for looking at nucleation phenomena, where you are +interested in using studying the behavior of atoms in small aggregates or nuclei. In these sorts of +problems you might be interested in the distribution of the sizes of the clusters in your system. A detailed description of this CV can be found in \cite tribello-clustering. \par Examples The input provided below calculates the local q6 Steinhardt parameter on each atom. The coordination number -that atoms with a high value for the local q6 Steinhardt parameter have with other atoms that have a high +that atoms with a high value for the local q6 Steinhardt parameter have with other atoms that have a high value for the local q6 Steinhardt parameter is then computed. A contact matrix is then computed that measures -whether atoms atoms \f$i\f$ and \f$j\f$ have a high value for this coordination number and if they are within -3.6 nm of each other. The connected components of this matrix are then found using a depth first clustering +whether atoms atoms \f$i\f$ and \f$j\f$ have a high value for this coordination number and if they are within +3.6 nm of each other. The connected components of this matrix are then found using a depth first clustering algorithm on the corresponding graph. The number of componets in this graph that contain more than 27 atoms is then computed. As discussed in \cite tribello-clustering this input was used to analyse the formation of a polycrystal of GeTe from amorphous GeTe. @@ -77,49 +77,49 @@ public: /// Do the calculation void calculate(); /// We can use ActionWithVessel to run all the calculation - void performTask( const unsigned& , const unsigned& , MultiValue& ) const ; + void performTask( const unsigned&, const unsigned&, MultiValue& ) const ; }; PLUMED_REGISTER_ACTION(ClusterDistribution,"CLUSTER_DISTRIBUTION") -void ClusterDistribution::registerKeywords( Keywords& keys ){ +void ClusterDistribution::registerKeywords( Keywords& keys ) { ClusterAnalysisBase::registerKeywords( keys ); keys.add("compulsory","TRANSFORM","none","the switching function to use to convert the crystallinity parameter to a number between zero and one"); keys.addFlag("INVERSE_TRANSFORM",false,"when TRANSFORM appears alone the input symmetry functions, \\f$x\\f$ are transformed used \\f$1-s(x)\\f$ " - "where \\f$s(x)\\f$ is a switching function. When this option is used you instead transform using \\f$s(x)\\f$ only."); - keys.use("MORE_THAN"); keys.use("LESS_THAN"); keys.use("BETWEEN"); - keys.use("HISTOGRAM"); keys.use("ALT_MIN"); keys.use("MIN"); keys.use("MAX"); + "where \\f$s(x)\\f$ is a switching function. When this option is used you instead transform using \\f$s(x)\\f$ only."); + keys.use("MORE_THAN"); keys.use("LESS_THAN"); keys.use("BETWEEN"); + keys.use("HISTOGRAM"); keys.use("ALT_MIN"); keys.use("MIN"); keys.use("MAX"); } ClusterDistribution::ClusterDistribution(const ActionOptions&ao): -Action(ao), -ClusterAnalysisBase(ao), -nderivatives(0) + Action(ao), + ClusterAnalysisBase(ao), + nderivatives(0) { - use_switch=false; - std::string input, errors; parse("TRANSFORM",input); - if( input!="none" ){ - use_switch=true; sf.set( input, errors ); - if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); - } - parseFlag("INVERSE_TRANSFORM",inverse); - if( inverse && !use_switch ) error("INVERSE_TRANSFORM option was specified but no TRANSOFRM switching function was given"); - - // Create all tasks by copying those from underlying DFS object (which is actually MultiColvar) - for(unsigned i=0;i<getNumberOfNodes();++i) addTaskToList(i); - - // And now finish the setup of everything in the base - std::vector<AtomNumber> fake_atoms; setupMultiColvarBase( fake_atoms ); + use_switch=false; + std::string input, errors; parse("TRANSFORM",input); + if( input!="none" ) { + use_switch=true; sf.set( input, errors ); + if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); + } + parseFlag("INVERSE_TRANSFORM",inverse); + if( inverse && !use_switch ) error("INVERSE_TRANSFORM option was specified but no TRANSOFRM switching function was given"); + + // Create all tasks by copying those from underlying DFS object (which is actually MultiColvar) + for(unsigned i=0; i<getNumberOfNodes(); ++i) addTaskToList(i); + + // And now finish the setup of everything in the base + std::vector<AtomNumber> fake_atoms; setupMultiColvarBase( fake_atoms ); } -void ClusterDistribution::calculate(){ - // Activate the relevant tasks - nderivatives = getNumberOfDerivatives(); - deactivateAllTasks(); - for(unsigned i=0;i<getNumberOfClusters();++i) taskFlags[i]=1; - lockContributors(); - // Now do the calculation - runAllTasks(); +void ClusterDistribution::calculate() { + // Activate the relevant tasks + nderivatives = getNumberOfDerivatives(); + deactivateAllTasks(); + for(unsigned i=0; i<getNumberOfClusters(); ++i) taskFlags[i]=1; + lockContributors(); + // Now do the calculation + runAllTasks(); } void ClusterDistribution::performTask( const unsigned& task_index, const unsigned& current, MultiValue& myvals ) const { @@ -127,33 +127,33 @@ void ClusterDistribution::performTask( const unsigned& task_index, const unsigne // This deals with filters if( myatoms.size()==1 && !nodeIsActive(myatoms[0]) ) return ; - std::vector<double> vals( getNumberOfQuantities() ); + std::vector<double> vals( getNumberOfQuantities() ); MultiValue tvals( getNumberOfQuantities(), nderivatives ); // And this builds everything for this particular atom - double vv, df, tval=0; - for(unsigned j=0;j<myatoms.size();++j){ - unsigned i=myatoms[j]; - getPropertiesOfNode( i, vals ); - if( use_switch && !inverse ){ - vv = 1.0 - sf.calculate( vals[1], df ); - tval += vals[0]*vv; df=-df*vals[1]; - } else if( use_switch ){ - vv = sf.calculate( vals[1], df ); - tval += vals[0]*vv; df=df*vals[1]; - } else { - tval += vals[0]*vals[1]; df=1.; vv=vals[1]; - } - if( !doNotCalculateDerivatives() ){ - getNodePropertyDerivatives( i, tvals ); - for(unsigned k=0;k<tvals.getNumberActive();++k){ - unsigned kat=tvals.getActiveIndex(k); - myvals.addDerivative( 1, kat, vals[0]*df*tvals.getDerivative(1,kat) + vv*tvals.getDerivative(0,kat) ); - } - tvals.clearAll(); + double vv, df, tval=0; + for(unsigned j=0; j<myatoms.size(); ++j) { + unsigned i=myatoms[j]; + getPropertiesOfNode( i, vals ); + if( use_switch && !inverse ) { + vv = 1.0 - sf.calculate( vals[1], df ); + tval += vals[0]*vv; df=-df*vals[1]; + } else if( use_switch ) { + vv = sf.calculate( vals[1], df ); + tval += vals[0]*vv; df=df*vals[1]; + } else { + tval += vals[0]*vals[1]; df=1.; vv=vals[1]; + } + if( !doNotCalculateDerivatives() ) { + getNodePropertyDerivatives( i, tvals ); + for(unsigned k=0; k<tvals.getNumberActive(); ++k) { + unsigned kat=tvals.getActiveIndex(k); + myvals.addDerivative( 1, kat, vals[0]*df*tvals.getDerivative(1,kat) + vv*tvals.getDerivative(0,kat) ); } + tvals.clearAll(); + } } - myvals.setValue( 0, 1.0 ); myvals.setValue( 1, tval ); + myvals.setValue( 0, 1.0 ); myvals.setValue( 1, tval ); } } diff --git a/src/adjmat/ClusterProperties.cpp b/src/adjmat/ClusterProperties.cpp index cd3528b44..9a0d38e5b 100644 --- a/src/adjmat/ClusterProperties.cpp +++ b/src/adjmat/ClusterProperties.cpp @@ -25,13 +25,13 @@ //+PLUMEDOC CONCOMP CLUSTER_PROPERTIES /* -Calculate properties of the distribution of some quantities that are part of a connected component +Calculate properties of the distribution of some quantities that are part of a connected component -This collective variable was developed for looking at nucleation phenomena, where you are -interested in using studying the behavior of atoms in small aggregates or nuclei. In these sorts of -problems you might be interested in the degree the atoms in a nucleus have adopted their crystalline -structure or (in the case of heterogenous nucleation of a solute from a solvent) you might be -interested in how many atoms are present in the largest cluster \cite tribello-clustering. +This collective variable was developed for looking at nucleation phenomena, where you are +interested in using studying the behavior of atoms in small aggregates or nuclei. In these sorts of +problems you might be interested in the degree the atoms in a nucleus have adopted their crystalline +structure or (in the case of heterogenous nucleation of a solute from a solvent) you might be +interested in how many atoms are present in the largest cluster \cite tribello-clustering. \par Examples @@ -43,10 +43,10 @@ numbers for the atoms in this largest connected component are then computed and file. The way this input can be used is described in detail in \cite tribello-clustering. \verbatim -lq: COORDINATIONNUMBER SPECIES=1-100 SWITCH={CUBIC D_0=0.45 D_MAX=0.55} LOWMEM -cm: CONTACT_MATRIX ATOMS=lq SWITCH={CUBIC D_0=0.45 D_MAX=0.55} -dfs: DFSCLUSTERING MATRIX=cm -clust1: CLUSTER_PROPERTIES CLUSTERS=dfs CLUSTER=1 SUM +lq: COORDINATIONNUMBER SPECIES=1-100 SWITCH={CUBIC D_0=0.45 D_MAX=0.55} LOWMEM +cm: CONTACT_MATRIX ATOMS=lq SWITCH={CUBIC D_0=0.45 D_MAX=0.55} +dfs: DFSCLUSTERING MATRIX=cm +clust1: CLUSTER_PROPERTIES CLUSTERS=dfs CLUSTER=1 SUM PRINT ARG=clust1.* FILE=colvar \endverbatim @@ -68,53 +68,53 @@ public: /// Do the calculation void calculate(); /// We can use ActionWithVessel to run all the calculation - void performTask( const unsigned& , const unsigned& , MultiValue& ) const ; + void performTask( const unsigned&, const unsigned&, MultiValue& ) const ; }; PLUMED_REGISTER_ACTION(ClusterProperties,"CLUSTER_PROPERTIES") -void ClusterProperties::registerKeywords( Keywords& keys ){ +void ClusterProperties::registerKeywords( Keywords& keys ) { ClusterAnalysisBase::registerKeywords( keys ); keys.add("compulsory","CLUSTER","1","which cluster would you like to look at 1 is the largest cluster, 2 is the second largest, 3 is the the third largest and so on."); keys.use("MEAN"); keys.use("MORE_THAN"); keys.use("LESS_THAN"); if( keys.reserved("VMEAN") ) keys.use("VMEAN"); if( keys.reserved("VSUM") ) keys.use("VSUM"); - keys.use("BETWEEN"); keys.use("HISTOGRAM"); keys.use("MOMENTS"); keys.use("ALT_MIN"); - keys.use("MIN"); keys.use("MAX"); keys.use("SUM");keys.use("LOWEST"); keys.use("HIGHEST"); + keys.use("BETWEEN"); keys.use("HISTOGRAM"); keys.use("MOMENTS"); keys.use("ALT_MIN"); + keys.use("MIN"); keys.use("MAX"); keys.use("SUM"); keys.use("LOWEST"); keys.use("HIGHEST"); } ClusterProperties::ClusterProperties(const ActionOptions&ao): -Action(ao), -ClusterAnalysisBase(ao) + Action(ao), + ClusterAnalysisBase(ao) { - // Find out which cluster we want - parse("CLUSTER",clustr); + // Find out which cluster we want + parse("CLUSTER",clustr); - if( clustr<1 ) error("cannot look for a cluster larger than the largest cluster"); - if( clustr>getNumberOfNodes() ) error("cluster selected is invalid - too few atoms in system"); + if( clustr<1 ) error("cannot look for a cluster larger than the largest cluster"); + if( clustr>getNumberOfNodes() ) error("cluster selected is invalid - too few atoms in system"); - // Create all tasks by copying those from underlying DFS object (which is actually MultiColvar) - for(unsigned i=0;i<getNumberOfNodes();++i) addTaskToList(i); + // Create all tasks by copying those from underlying DFS object (which is actually MultiColvar) + for(unsigned i=0; i<getNumberOfNodes(); ++i) addTaskToList(i); - // And now finish the setup of everything in the base - std::vector<AtomNumber> fake_atoms; setupMultiColvarBase( fake_atoms ); + // And now finish the setup of everything in the base + std::vector<AtomNumber> fake_atoms; setupMultiColvarBase( fake_atoms ); } -void ClusterProperties::calculate(){ - // Retrieve the atoms in the largest cluster - std::vector<unsigned> myatoms; retrieveAtomsInCluster( clustr, myatoms ); - // Activate the relevant tasks - deactivateAllTasks(); - for(unsigned i=0;i<myatoms.size();++i) taskFlags[myatoms[i]]=1; - lockContributors(); - // Now do the calculation - runAllTasks(); +void ClusterProperties::calculate() { + // Retrieve the atoms in the largest cluster + std::vector<unsigned> myatoms; retrieveAtomsInCluster( clustr, myatoms ); + // Activate the relevant tasks + deactivateAllTasks(); + for(unsigned i=0; i<myatoms.size(); ++i) taskFlags[myatoms[i]]=1; + lockContributors(); + // Now do the calculation + runAllTasks(); } void ClusterProperties::performTask( const unsigned& task_index, const unsigned& current, MultiValue& myvals ) const { - std::vector<double> vals( myvals.getNumberOfValues() ); getPropertiesOfNode( current, vals ); - if( !doNotCalculateDerivatives() ) getNodePropertyDerivatives( current, myvals ); - for(unsigned k=0;k<vals.size();++k) myvals.setValue( k, vals[k] ); + std::vector<double> vals( myvals.getNumberOfValues() ); getPropertiesOfNode( current, vals ); + if( !doNotCalculateDerivatives() ) getNodePropertyDerivatives( current, myvals ); + for(unsigned k=0; k<vals.size(); ++k) myvals.setValue( k, vals[k] ); } } diff --git a/src/adjmat/ClusterSize.cpp b/src/adjmat/ClusterSize.cpp index e24505062..b0b22621d 100644 --- a/src/adjmat/ClusterSize.cpp +++ b/src/adjmat/ClusterSize.cpp @@ -24,19 +24,19 @@ //+PLUMEDOC CONCOMP CLUSTER_NATOMS /* -Gives the number of atoms in the connected component +Gives the number of atoms in the connected component -As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the -so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether +As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the +so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether or not the \f$i\f$th and \f$j\f$th atoms/molecules from a set of \f$N\f$ atoms/molecules are adjacent or not. When analysing these matrix we can treat them as a graph and find connected components using some clustering algorithm. This action is used in tandem with this form of analysis -to output the number of atoms that are connected together in a particular connected component. It is important to note that the quantity that is +to output the number of atoms that are connected together in a particular connected component. It is important to note that the quantity that is output by this action is not differentiable. As such it cannot be used as a collective variable in a biased simulation. \par Examples The following input uses PLUMED to calculate a adjacency matrix that connects a pair of atoms if they both have a coordination number that is greater -than 2.0 and if they are within 6.0 nm of each other. Depth first search clustering is used to find the connected components in this matrix and then +than 2.0 and if they are within 6.0 nm of each other. Depth first search clustering is used to find the connected components in this matrix and then the number of atoms in the largest cluster is found. This quantity is then output to a file called colvar \verbatim @@ -78,35 +78,35 @@ public: PLUMED_REGISTER_ACTION(ClusterSize,"CLUSTER_NATOMS") -void ClusterSize::registerKeywords( Keywords& keys ){ +void ClusterSize::registerKeywords( Keywords& keys ) { ClusterAnalysisBase::registerKeywords( keys ); keys.add("compulsory","CLUSTER","1","which cluster would you like to look at 1 is the largest cluster, 2 is the second largest, 3 is the the third largest and so on."); } ClusterSize::ClusterSize(const ActionOptions&ao): -Action(ao), -ClusterAnalysisBase(ao) + Action(ao), + ClusterAnalysisBase(ao) { - // Find out which cluster we want - parse("CLUSTER",clustr); + // Find out which cluster we want + parse("CLUSTER",clustr); - if( clustr<1 ) error("cannot look for a cluster larger than the largest cluster"); - if( clustr>getNumberOfNodes() ) error("cluster selected is invalid - too few atoms in system"); + if( clustr<1 ) error("cannot look for a cluster larger than the largest cluster"); + if( clustr>getNumberOfNodes() ) error("cluster selected is invalid - too few atoms in system"); - // Create all tasks by copying those from underlying DFS object (which is actually MultiColvar) - for(unsigned i=0;i<getNumberOfNodes();++i) addTaskToList(i); - // And now finish the setup of everything in the base - std::vector<AtomNumber> fake_atoms; setupMultiColvarBase( fake_atoms ); - addValue(); setNotPeriodic(); + // Create all tasks by copying those from underlying DFS object (which is actually MultiColvar) + for(unsigned i=0; i<getNumberOfNodes(); ++i) addTaskToList(i); + // And now finish the setup of everything in the base + std::vector<AtomNumber> fake_atoms; setupMultiColvarBase( fake_atoms ); + addValue(); setNotPeriodic(); } -void ClusterSize::turnOnDerivatives(){ - error("cannot calculate derivatives of number of atoms in cluster. This quantity is not differentiable"); +void ClusterSize::turnOnDerivatives() { + error("cannot calculate derivatives of number of atoms in cluster. This quantity is not differentiable"); } -void ClusterSize::calculate(){ - // Retrieve the atoms in the largest cluster - std::vector<unsigned> myatoms; retrieveAtomsInCluster( clustr, myatoms ); setValue( myatoms.size() ); +void ClusterSize::calculate() { + // Retrieve the atoms in the largest cluster + std::vector<unsigned> myatoms; retrieveAtomsInCluster( clustr, myatoms ); setValue( myatoms.size() ); } } diff --git a/src/adjmat/ClusterWithSurface.cpp b/src/adjmat/ClusterWithSurface.cpp index 21c2e3a5c..ab472eee5 100644 --- a/src/adjmat/ClusterWithSurface.cpp +++ b/src/adjmat/ClusterWithSurface.cpp @@ -24,24 +24,24 @@ #include "AdjacencyMatrixBase.h" #include "core/ActionRegister.h" -//+PLUMEDOC MATRIXF CLUSTER_WITHSURFACE +//+PLUMEDOC MATRIXF CLUSTER_WITHSURFACE /* Take a connected component that was found using a clustering algorithm and create a new cluster that contains those atoms that are in the cluster together with those atoms that are within a certain cutoff of the cluster. -As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the -so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether +As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the +so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether or not the \f$i\f$th and \f$j\f$th atoms/molecules from a set of \f$N\f$ atoms/molecules are adjacent or not. When analysing these matrix we can treat them as a graph and find connected components using some clustering algorithm. This action is used in tandem with this form of analysis -and takes one of the connected components that was found during this analysis and creates a new cluster that includes all the atoms within the +and takes one of the connected components that was found during this analysis and creates a new cluster that includes all the atoms within the connected component that was found together that were within a certain cutoff distance of the atoms in the connected component. This form of analysis has been used sucessfully in the forward flux sampling simulations described in this paper \cite gab-ice-kaolinite \par Examples -The following input uses PLUMED to calculate a adjacency matrix that connects a pair of atoms if they both have a coordination number that is less +The following input uses PLUMED to calculate a adjacency matrix that connects a pair of atoms if they both have a coordination number that is less than 13.5 and if they are within 0.38 nm of each other. Depth first search clustering is used to find the connected components in this matrix. The -number of atoms with indices that are between 1 and 1996 and that are either in the second largest cluster or that are within within 0.3 nm of one of the -atoms within the the second largest cluster are then counted and this number of atoms is output to a file called size. In addition the indices of the atoms +number of atoms with indices that are between 1 and 1996 and that are either in the second largest cluster or that are within within 0.3 nm of one of the +atoms within the the second largest cluster are then counted and this number of atoms is output to a file called size. In addition the indices of the atoms that were counted are output to a file called dfs2.dat. \verbatim @@ -88,45 +88,45 @@ public: /// unsigned getNumberOfQuantities() const ; /// Do the calculation - void performClustering(){}; + void performClustering() {}; /// - double getCutoffForConnection() const ; + double getCutoffForConnection() const ; /// Vector getPositionOfAtomForLinkCells( const unsigned& taskIndex ) const ; }; PLUMED_REGISTER_ACTION(ClusterWithSurface,"CLUSTER_WITHSURFACE") -void ClusterWithSurface::registerKeywords( Keywords& keys ){ +void ClusterWithSurface::registerKeywords( Keywords& keys ) { ClusteringBase::registerKeywords( keys ); keys.remove("MATRIX"); keys.add("compulsory","CLUSTERS","the label of the action that does the clustering"); keys.add("compulsory","RCUT_SURF","you also have the option to find the atoms on the surface of the cluster. An atom must be within this distance of one of the atoms " - "of the cluster in order to be considered a surface atom"); + "of the cluster in order to be considered a surface atom"); } ClusterWithSurface::ClusterWithSurface(const ActionOptions&ao): -Action(ao), -ClusteringBase(ao) + Action(ao), + ClusteringBase(ao) { - std::vector<AtomNumber> fake_atoms; - if( !parseMultiColvarAtomList("CLUSTERS",-1,fake_atoms ) ) error("unable to find CLUSTERS input"); - if( mybasemulticolvars.size()!=1 ) error("should be exactly one multicolvar input"); + std::vector<AtomNumber> fake_atoms; + if( !parseMultiColvarAtomList("CLUSTERS",-1,fake_atoms ) ) error("unable to find CLUSTERS input"); + if( mybasemulticolvars.size()!=1 ) error("should be exactly one multicolvar input"); - // Retrieve the adjacency matrix of interest - atom_lab.resize(0); myclusters = dynamic_cast<ClusteringBase*>( mybasemulticolvars[0] ); - if( !myclusters ) error( mybasemulticolvars[0]->getLabel() + " does not calculate clusters"); + // Retrieve the adjacency matrix of interest + atom_lab.resize(0); myclusters = dynamic_cast<ClusteringBase*>( mybasemulticolvars[0] ); + if( !myclusters ) error( mybasemulticolvars[0]->getLabel() + " does not calculate clusters"); - // Setup switching function for surface atoms - double rcut_surf; parse("RCUT_SURF",rcut_surf); - if( rcut_surf>0 ) log.printf(" counting surface atoms that are within %f of the cluster atoms \n",rcut_surf); - rcut_surf2=rcut_surf*rcut_surf; + // Setup switching function for surface atoms + double rcut_surf; parse("RCUT_SURF",rcut_surf); + if( rcut_surf>0 ) log.printf(" counting surface atoms that are within %f of the cluster atoms \n",rcut_surf); + rcut_surf2=rcut_surf*rcut_surf; - // And now finish the setup of everything in the base - setupMultiColvarBase( fake_atoms ); + // And now finish the setup of everything in the base + setupMultiColvarBase( fake_atoms ); } -unsigned ClusterWithSurface::getNumberOfDerivatives(){ +unsigned ClusterWithSurface::getNumberOfDerivatives() { return myclusters->getNumberOfDerivatives(); } @@ -161,26 +161,26 @@ void ClusterWithSurface::retrieveAtomsInCluster( const unsigned& clust, std::vec // Prevent double counting std::vector<bool> incluster( getNumberOfNodes(), false ); - for(unsigned i=0;i<tmpat.size();++i) incluster[tmpat[i]]=true; + for(unsigned i=0; i<tmpat.size(); ++i) incluster[tmpat[i]]=true; // Find the atoms in the the clusters - std::vector<bool> surface_atom( getNumberOfNodes(), false ); - for(unsigned i=0;i<tmpat.size();++i){ - for(unsigned j=0;j<getNumberOfNodes();++j){ - if( incluster[j] ) continue; - double dist2=getSeparation( getPosition(tmpat[i]), getPosition(j) ).modulo2(); - if( dist2<rcut_surf2 ){ surface_atom[j]=true; } - } + std::vector<bool> surface_atom( getNumberOfNodes(), false ); + for(unsigned i=0; i<tmpat.size(); ++i) { + for(unsigned j=0; j<getNumberOfNodes(); ++j) { + if( incluster[j] ) continue; + double dist2=getSeparation( getPosition(tmpat[i]), getPosition(j) ).modulo2(); + if( dist2<rcut_surf2 ) { surface_atom[j]=true; } + } } - unsigned nsurf_at=0; - for(unsigned j=0;j<getNumberOfNodes();++j){ - if( surface_atom[j] ) nsurf_at++; + unsigned nsurf_at=0; + for(unsigned j=0; j<getNumberOfNodes(); ++j) { + if( surface_atom[j] ) nsurf_at++; } myatoms.resize( nsurf_at + tmpat.size() ); - for(unsigned i=0;i<tmpat.size();++i) myatoms[i]=tmpat[i]; + for(unsigned i=0; i<tmpat.size(); ++i) myatoms[i]=tmpat[i]; unsigned nn=tmpat.size(); - for(unsigned j=0;j<getNumberOfNodes();++j){ - if( surface_atom[j] ){ myatoms[nn]=j; nn++; } + for(unsigned j=0; j<getNumberOfNodes(); ++j) { + if( surface_atom[j] ) { myatoms[nn]=j; nn++; } } plumed_assert( nn==myatoms.size() ); } diff --git a/src/adjmat/ClusteringBase.cpp b/src/adjmat/ClusteringBase.cpp index b42061f1c..8e21ee16f 100644 --- a/src/adjmat/ClusteringBase.cpp +++ b/src/adjmat/ClusteringBase.cpp @@ -26,53 +26,53 @@ namespace PLMD { namespace adjmat { -void ClusteringBase::registerKeywords( Keywords& keys ){ +void ClusteringBase::registerKeywords( Keywords& keys ) { ActionWithInputMatrix::registerKeywords( keys ); } ClusteringBase::ClusteringBase(const ActionOptions&ao): -Action(ao), -ActionWithInputMatrix(ao), -number_of_cluster(-1) + Action(ao), + ActionWithInputMatrix(ao), + number_of_cluster(-1) { - if( getAdjacencyVessel() ){ - cluster_sizes.resize(getNumberOfNodes()); which_cluster.resize(getNumberOfNodes()); - if( getNumberOfNodeTypes()!=1 ) error("should only be running clustering with one base multicolvar in function"); - if( !getAdjacencyVessel()->undirectedGraph() ) error("input contact matrix is incompatible with clustering"); - } - if( keywords.exists("MATRIX") ){ - std::vector<AtomNumber> fake_atoms; setupMultiColvarBase( fake_atoms ); - } + if( getAdjacencyVessel() ) { + cluster_sizes.resize(getNumberOfNodes()); which_cluster.resize(getNumberOfNodes()); + if( getNumberOfNodeTypes()!=1 ) error("should only be running clustering with one base multicolvar in function"); + if( !getAdjacencyVessel()->undirectedGraph() ) error("input contact matrix is incompatible with clustering"); + } + if( keywords.exists("MATRIX") ) { + std::vector<AtomNumber> fake_atoms; setupMultiColvarBase( fake_atoms ); + } } -void ClusteringBase::turnOnDerivatives(){ - // Check base multicolvar isn't density probably other things shouldn't be allowed here as well - if( (getAdjacencyVessel()->getMatrixAction())->getNumberOfBaseMultiColvars()>0 ){ - if( getBaseMultiColvar(0)->isDensity() ) error("DFS clustering cannot be differentiated if base multicolvar is DENSITY"); - } +void ClusteringBase::turnOnDerivatives() { + // Check base multicolvar isn't density probably other things shouldn't be allowed here as well + if( (getAdjacencyVessel()->getMatrixAction())->getNumberOfBaseMultiColvars()>0 ) { + if( getBaseMultiColvar(0)->isDensity() ) error("DFS clustering cannot be differentiated if base multicolvar is DENSITY"); + } - // Ensure that derivatives are turned on in base classes - ActionWithInputMatrix::turnOnDerivatives(); + // Ensure that derivatives are turned on in base classes + ActionWithInputMatrix::turnOnDerivatives(); } -void ClusteringBase::calculate(){ - // All the clusters have zero size initially - for(unsigned i=0;i<cluster_sizes.size();++i){ cluster_sizes[i].first=0; cluster_sizes[i].second=i; } - // Do the clustering bit - performClustering(); - // Order the clusters in the system by size (this returns ascending order ) - std::sort( cluster_sizes.begin(), cluster_sizes.end() ); +void ClusteringBase::calculate() { + // All the clusters have zero size initially + for(unsigned i=0; i<cluster_sizes.size(); ++i) { cluster_sizes[i].first=0; cluster_sizes[i].second=i; } + // Do the clustering bit + performClustering(); + // Order the clusters in the system by size (this returns ascending order ) + std::sort( cluster_sizes.begin(), cluster_sizes.end() ); } void ClusteringBase::retrieveAtomsInCluster( const unsigned& clust, std::vector<unsigned>& myatoms ) const { - unsigned n=0; myatoms.resize( cluster_sizes[cluster_sizes.size() - clust].first ); - for(unsigned i=0;i<getNumberOfNodes();++i){ - if( which_cluster[i]==cluster_sizes[cluster_sizes.size() - clust].second ){ myatoms[n]=i; n++; } - } + unsigned n=0; myatoms.resize( cluster_sizes[cluster_sizes.size() - clust].first ); + for(unsigned i=0; i<getNumberOfNodes(); ++i) { + if( which_cluster[i]==cluster_sizes[cluster_sizes.size() - clust].second ) { myatoms[n]=i; n++; } + } } bool ClusteringBase::areConnected( const unsigned& iatom, const unsigned& jatom ) const { - return getAdjacencyVessel()->nodesAreConnected( iatom, jatom ); + return getAdjacencyVessel()->nodesAreConnected( iatom, jatom ); } double ClusteringBase::getCutoffForConnection() const { diff --git a/src/adjmat/ClusteringBase.h b/src/adjmat/ClusteringBase.h index 11c0bc14c..741ac9046 100644 --- a/src/adjmat/ClusteringBase.h +++ b/src/adjmat/ClusteringBase.h @@ -32,7 +32,7 @@ class ClusteringBase : public ActionWithInputMatrix { protected: /// Vector that stores the sizes of the current set of clusters std::vector< std::pair<unsigned,unsigned> > cluster_sizes; -/// Used to identify the cluster we are working on +/// Used to identify the cluster we are working on int number_of_cluster; /// Vector that identifies the cluster each atom belongs to std::vector<unsigned> which_cluster; @@ -47,15 +47,15 @@ public: bool areConnected( const unsigned& iatom, const unsigned& jatom ) const ; /// Do the calculation void calculate(); -/// Do the clustering +/// Do the clustering virtual void performClustering()=0; /// Get the number of clusters that have been found unsigned getNumberOfClusters() const ; /// Get the atoms in one of the clusters virtual void retrieveAtomsInCluster( const unsigned& clust, std::vector<unsigned>& myatoms ) const ; /// Do nothing for apply here - void apply(){} -/// Get the cutoff + void apply() {} +/// Get the cutoff virtual double getCutoffForConnection() const ; }; diff --git a/src/adjmat/ContactAlignedMatrix.cpp b/src/adjmat/ContactAlignedMatrix.cpp index e1343f5a3..e1bdfcdba 100644 --- a/src/adjmat/ContactAlignedMatrix.cpp +++ b/src/adjmat/ContactAlignedMatrix.cpp @@ -23,12 +23,12 @@ #include "core/ActionRegister.h" #include "tools/Matrix.h" -//+PLUMEDOC MATRIX ALIGNED_MATRIX +//+PLUMEDOC MATRIX ALIGNED_MATRIX /* Adjacency matrix in which two molecule are adjacent if they are within a certain cutoff and if they have the same orientation. -As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the -so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether +As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the +so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether or not the \f$i\f$th and \f$j\f$th atoms/molecules from a set of \f$N\f$ atoms/molecules are adjacent or not. These matrices can then be further analysed using a number of other algorithms as is detailed in \cite tribello-clustering. @@ -38,29 +38,29 @@ For this action the elements of the adjacency matrix are calculated using: a_{ij} = \sigma_1( |\mathbf{r}_{ij}| ) \sigma_2( \mathbf{v}_i . \mathbf{v}_j ) \f] -This form of adjacency matrix can only be used if the input species are objects that lie at a point in space and that have an orientation, \f$\mathbf{v}\f$. -These orientations might represent the -orientation of a molecule, which could be calculated using \ref MOLECULES or \ref PLANES, or it might be the complex vectors calculated using the +This form of adjacency matrix can only be used if the input species are objects that lie at a point in space and that have an orientation, \f$\mathbf{v}\f$. +These orientations might represent the +orientation of a molecule, which could be calculated using \ref MOLECULES or \ref PLANES, or it might be the complex vectors calculated using the Steinhardt parameters \ref Q3, \ref Q4 or \ref Q6. In the expression above \f$\mathbf{r}_{ij}\f$ is the vector connecting the points in space where objects \f$i\f$ and \f$j\f$ find themselves and \f$\sigma_1\f$ is a \ref switchingfunction that acts upon the magnitude of this vector. -\f$\sigma_2\f$ is a second \ref switchingfunction that acts on the dot product of the directors of the vectors that define the orientations of -objects \f$i\f$ and \f$j\f$. +\f$\sigma_2\f$ is a second \ref switchingfunction that acts on the dot product of the directors of the vectors that define the orientations of +objects \f$i\f$ and \f$j\f$. \par Examples The example input below is necessarily but gives you an idea of what can be achieved using this action. -The orientations and positions of four molecules are defined using the \ref MOLECULES action as the position of the +The orientations and positions of four molecules are defined using the \ref MOLECULES action as the position of the centeres of mass of the two atoms specified and the direction of the vector connecting the two atoms that were specified. -A \f$4 \times 4\f$ matrix is then computed using the formula above. The \f$ij\f$-element of this matrix tells us whether +A \f$4 \times 4\f$ matrix is then computed using the formula above. The \f$ij\f$-element of this matrix tells us whether or not atoms \f$i\f$ and \f$j\f$ are within 0.1 nm of each other and whether or not the dot-product of their orientation vectors -is greater than 0.5. The sum of the rows of this matrix are then computed. The sums of the \f$i\f$th row of this matrix tells us how -many of the molecules that are within the first coordination sphere of molecule \f$i\f$ have an orientation that is similar to that of -molecule \f$i\f$. We thus calculate the number of these "coordination numbers" that are greater than 1.0 and output this quantity to a file. +is greater than 0.5. The sum of the rows of this matrix are then computed. The sums of the \f$i\f$th row of this matrix tells us how +many of the molecules that are within the first coordination sphere of molecule \f$i\f$ have an orientation that is similar to that of +molecule \f$i\f$. We thus calculate the number of these "coordination numbers" that are greater than 1.0 and output this quantity to a file. \verbatim m1: MOLECULES MOL1=1,2 MOL2=3,4 MOL3=5,6 MOL4=7,8 mat: ALIGNED_MATRIX ATOMS=m1 SWITCH={RATIONAL R_0=0.1} ORIENTATION_SWITCH={RATIONAL R_0=0.1 D_MAX=0.5} -rr: ROWSUMS MATRIX=mat MORE_THAN={RATIONAL D_0=1.0 R_0=0.1} +rr: ROWSUMS MATRIX=mat MORE_THAN={RATIONAL D_0=1.0 R_0=0.1} PRINT ARG=rr.* FILE=colvar \endverbatim @@ -72,48 +72,48 @@ namespace adjmat { class ContactAlignedMatrix : public AlignedMatrixBase { private: - Matrix<SwitchingFunction> sf; + Matrix<SwitchingFunction> sf; public: - /// - static void registerKeywords( Keywords& keys ); - /// - explicit ContactAlignedMatrix(const ActionOptions&); - void readOrientationConnector( const unsigned& i, const unsigned& j, const std::vector<std::string>& desc ); - double computeVectorFunction( const unsigned& iv, const unsigned& jv, - const Vector& conn, const std::vector<double>& vec1, const std::vector<double>& vec2, - Vector& dconn, std::vector<double>& dvec1, std::vector<double>& dvec2 ) const ; + /// + static void registerKeywords( Keywords& keys ); + /// + explicit ContactAlignedMatrix(const ActionOptions&); + void readOrientationConnector( const unsigned& i, const unsigned& j, const std::vector<std::string>& desc ); + double computeVectorFunction( const unsigned& iv, const unsigned& jv, + const Vector& conn, const std::vector<double>& vec1, const std::vector<double>& vec2, + Vector& dconn, std::vector<double>& dvec1, std::vector<double>& dvec2 ) const ; }; PLUMED_REGISTER_ACTION(ContactAlignedMatrix,"ALIGNED_MATRIX") -void ContactAlignedMatrix::registerKeywords( Keywords& keys ){ - AlignedMatrixBase::registerKeywords( keys ); - keys.add("numbered","ORIENTATION_SWITCH","A switching function that transforms the dot product of the input vectors."); +void ContactAlignedMatrix::registerKeywords( Keywords& keys ) { + AlignedMatrixBase::registerKeywords( keys ); + keys.add("numbered","ORIENTATION_SWITCH","A switching function that transforms the dot product of the input vectors."); } ContactAlignedMatrix::ContactAlignedMatrix( const ActionOptions& ao ): -Action(ao), -AlignedMatrixBase(ao) + Action(ao), + AlignedMatrixBase(ao) { - unsigned nrows, ncols, ig; retrieveTypeDimensions( nrows, ncols, ig ); - sf.resize( nrows, ncols ); - parseConnectionDescriptions("ORIENTATION_SWITCH",false,0); + unsigned nrows, ncols, ig; retrieveTypeDimensions( nrows, ncols, ig ); + sf.resize( nrows, ncols ); + parseConnectionDescriptions("ORIENTATION_SWITCH",false,0); } -void ContactAlignedMatrix::readOrientationConnector( const unsigned& i, const unsigned& j, const std::vector<std::string>& desc ){ - plumed_assert( desc.size()==1 ); std::string errors; sf(j,i).set(desc[0],errors); - if( j!=i ) sf(i,j).set(desc[0],errors); - log.printf(" vectors in %u th and %u th groups must have a dot product that is greater than %s \n",i+1,j+1,(sf(i,j).description()).c_str() ); +void ContactAlignedMatrix::readOrientationConnector( const unsigned& i, const unsigned& j, const std::vector<std::string>& desc ) { + plumed_assert( desc.size()==1 ); std::string errors; sf(j,i).set(desc[0],errors); + if( j!=i ) sf(i,j).set(desc[0],errors); + log.printf(" vectors in %u th and %u th groups must have a dot product that is greater than %s \n",i+1,j+1,(sf(i,j).description()).c_str() ); } -double ContactAlignedMatrix::computeVectorFunction( const unsigned& iv, const unsigned& jv, - const Vector& conn, const std::vector<double>& vec1, const std::vector<double>& vec2, - Vector& dconn, std::vector<double>& dvec1, std::vector<double>& dvec2 ) const { - double dot_df, dot=0; dconn.zero(); - for(unsigned k=2;k<vec1.size();++k) dot+=vec1[k]*vec2[k]; - double f_dot = sf(iv,jv).calculate( dot, dot_df ); - for(unsigned k=2;k<vec1.size();++k){ dvec1[k]=dot_df*vec2[k]; dvec2[k]=dot_df*vec1[k]; } - return f_dot; +double ContactAlignedMatrix::computeVectorFunction( const unsigned& iv, const unsigned& jv, + const Vector& conn, const std::vector<double>& vec1, const std::vector<double>& vec2, + Vector& dconn, std::vector<double>& dvec1, std::vector<double>& dvec2 ) const { + double dot_df, dot=0; dconn.zero(); + for(unsigned k=2; k<vec1.size(); ++k) dot+=vec1[k]*vec2[k]; + double f_dot = sf(iv,jv).calculate( dot, dot_df ); + for(unsigned k=2; k<vec1.size(); ++k) { dvec1[k]=dot_df*vec2[k]; dvec2[k]=dot_df*vec1[k]; } + return f_dot; } } diff --git a/src/adjmat/ContactMatrix.cpp b/src/adjmat/ContactMatrix.cpp index 78c16ae2d..1105a1aa2 100644 --- a/src/adjmat/ContactMatrix.cpp +++ b/src/adjmat/ContactMatrix.cpp @@ -25,12 +25,12 @@ #include "tools/SwitchingFunction.h" #include "tools/Matrix.h" -//+PLUMEDOC MATRIX CONTACT_MATRIX +//+PLUMEDOC MATRIX CONTACT_MATRIX /* Adjacency matrix in which two atoms are adjacent if they are within a certain cutoff. -As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the -so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether +As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the +so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether or not the \f$i\f$th and \f$j\f$th atoms/molecules from a set of \f$N\f$ atoms/molecules are adjacent or not. These matrices can then be further analysed using a number of other algorithms as is detailed in \cite tribello-clustering. @@ -82,24 +82,24 @@ public: PLUMED_REGISTER_ACTION(ContactMatrix,"CONTACT_MATRIX") -void ContactMatrix::registerKeywords( Keywords& keys ){ +void ContactMatrix::registerKeywords( Keywords& keys ) { AdjacencyMatrixBase::registerKeywords( keys ); keys.add("atoms","ATOMS","The list of atoms for which you would like to calculate the contact matrix. The atoms involved must be specified " - "as a list of labels of \\ref mcolv or labels of a \\ref multicolvarfunction actions. If you would just like to use " - "the atomic positions you can use a \\ref DENSITY command to specify a group of atoms. Specifying your atomic positions using labels of " - "other \\ref mcolv or \\ref multicolvarfunction commands is useful, however, as you can then exploit a much wider " - "variety of functions of the contact matrix as described in \\ref contactmatrix"); + "as a list of labels of \\ref mcolv or labels of a \\ref multicolvarfunction actions. If you would just like to use " + "the atomic positions you can use a \\ref DENSITY command to specify a group of atoms. Specifying your atomic positions using labels of " + "other \\ref mcolv or \\ref multicolvarfunction commands is useful, however, as you can then exploit a much wider " + "variety of functions of the contact matrix as described in \\ref contactmatrix"); keys.add("numbered","SWITCH","This keyword is used if you want to employ an alternative to the continuous swiching function defined above. " - "The following provides information on the \\ref switchingfunction that are available. " - "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); + "The following provides information on the \\ref switchingfunction that are available. " + "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); // I added these keywords so I can test the results I get for column and row sums against output from COORDINATIONNUMBERS /// These should never be used in production as I think they will be much slower than COORDINATIONNUMBERS keys.add("hidden","ATOMSA",""); keys.add("hidden","ATOMSB",""); } ContactMatrix::ContactMatrix( const ActionOptions& ao ): -Action(ao), -AdjacencyMatrixBase(ao) + Action(ao), + AdjacencyMatrixBase(ao) { // Read in the atoms and setup the matrix readMaxTwoSpeciesMatrix( "ATOMS", "ATOMSA", "ATOMSB", true ); @@ -110,17 +110,17 @@ AdjacencyMatrixBase(ao) // Find the largest sf cutoff double sfmax=switchingFunction(0,0).get_dmax(); - for(unsigned i=0;i<switchingFunction.nrows();++i){ - for(unsigned j=0;j<switchingFunction.ncols();++j){ - double tsf=switchingFunction(i,j).get_dmax(); - if( tsf>sfmax ) sfmax=tsf; - } + for(unsigned i=0; i<switchingFunction.nrows(); ++i) { + for(unsigned j=0; j<switchingFunction.ncols(); ++j) { + double tsf=switchingFunction(i,j).get_dmax(); + if( tsf>sfmax ) sfmax=tsf; + } } // And set the link cell cutoff setLinkCellCutoff( sfmax ); } -void ContactMatrix::setupConnector( const unsigned& id, const unsigned& i, const unsigned& j, const std::vector<std::string>& desc ){ +void ContactMatrix::setupConnector( const unsigned& id, const unsigned& i, const unsigned& j, const std::vector<std::string>& desc ) { plumed_assert( id==0 && desc.size()==1 ); std::string errors; switchingFunction(j,i).set(desc[0],errors); if( errors.length()!=0 ) error("problem reading switching function description " + errors); if( j!=i) switchingFunction(i,j).set(desc[0],errors); @@ -137,12 +137,12 @@ double ContactMatrix::compute( const unsigned& tindex, multicolvar::AtomValuePac Vector distance = getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); double dfunc, sw = switchingFunction( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) - ncol_t ).calculate( distance.modulo(), dfunc ); - if( !doNotCalculateDerivatives() ){ - Vector distance = getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); - double dfunc, sw = switchingFunction( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) - ncol_t ).calculate( distance.modulo(), dfunc ); - addAtomDerivatives( 1, 0, (-dfunc)*distance, myatoms ); - addAtomDerivatives( 1, 1, (+dfunc)*distance, myatoms ); - myatoms.addBoxDerivatives( 1, (-dfunc)*Tensor(distance,distance) ); + if( !doNotCalculateDerivatives() ) { + Vector distance = getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); + double dfunc, sw = switchingFunction( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) - ncol_t ).calculate( distance.modulo(), dfunc ); + addAtomDerivatives( 1, 0, (-dfunc)*distance, myatoms ); + addAtomDerivatives( 1, 1, (+dfunc)*distance, myatoms ); + myatoms.addBoxDerivatives( 1, (-dfunc)*Tensor(distance,distance) ); } return sw; } diff --git a/src/adjmat/DFSClustering.cpp b/src/adjmat/DFSClustering.cpp index 596641849..af0dc327e 100644 --- a/src/adjmat/DFSClustering.cpp +++ b/src/adjmat/DFSClustering.cpp @@ -24,8 +24,8 @@ #include "core/ActionRegister.h" #ifdef __PLUMED_HAS_BOOST_GRAPH -#include <boost/graph/adjacency_list.hpp> -#include <boost/graph/connected_components.hpp> +#include <boost/graph/adjacency_list.hpp> +#include <boost/graph/connected_components.hpp> #include <boost/graph/graph_utility.hpp> #endif @@ -33,8 +33,8 @@ /* Find the connected components of the matrix using the depth first search clustering algorithm. -As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the -so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether +As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the +so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether or not the \f$i\f$th and \f$j\f$th atoms/molecules from a set of \f$N\f$ atoms/molecules are adjacent or not. As detailed in \cite tribello-clustering these matrices provide a representation of a graph and can thus can be analysed using tools from graph theory. This particular action performs a depth first search clustering to find the connected components of this graph. You can read more about depth first search here: @@ -44,7 +44,7 @@ https://en.wikipedia.org/wiki/Depth-first_search This action is useful if you are looking at a phenomenon such as nucleation where the aim is to detect the sizes of the crystalline nuclei that have formed in your simulation cell. -\par Examples +\par Examples The input below calculates the coordination numbers of atoms 1-100 and then computes the an adjacency matrix whose elements measures whether atoms \f$i\f$ and \f$j\f$ are within 0.55 nm of each other. The action @@ -54,15 +54,15 @@ numbers for the atoms in this largest connected component are then computed and file. The way this input can be used is described in detail in \cite tribello-clustering. \verbatim -lq: COORDINATIONNUMBER SPECIES=1-100 SWITCH={CUBIC D_0=0.45 D_MAX=0.55} LOWMEM -cm: CONTACT_MATRIX ATOMS=lq SWITCH={CUBIC D_0=0.45 D_MAX=0.55} -dfs: DFSCLUSTERING MATRIX=cm -clust1: CLUSTER_PROPERTIES CLUSTERS=dfs CLUSTER=1 SUM +lq: COORDINATIONNUMBER SPECIES=1-100 SWITCH={CUBIC D_0=0.45 D_MAX=0.55} LOWMEM +cm: CONTACT_MATRIX ATOMS=lq SWITCH={CUBIC D_0=0.45 D_MAX=0.55} +dfs: DFSCLUSTERING MATRIX=cm +clust1: CLUSTER_PROPERTIES CLUSTERS=dfs CLUSTER=1 SUM PRINT ARG=clust1.* FILE=colvar \endverbatim */ -//+ENDPLUMEDOC +//+ENDPLUMEDOC namespace PLMD { namespace adjmat { @@ -93,67 +93,67 @@ public: PLUMED_REGISTER_ACTION(DFSClustering,"DFSCLUSTERING") -void DFSClustering::registerKeywords( Keywords& keys ){ +void DFSClustering::registerKeywords( Keywords& keys ) { ClusteringBase::registerKeywords( keys ); keys.add("compulsory","MAXCONNECT","0","maximum number of connections that can be formed by any given node in the graph. " - "By default this is set equal to zero and the number of connections is set equal to the number " - "of nodes. You only really need to set this if you are working with a very large system and " - "memory is at a premium"); + "By default this is set equal to zero and the number of connections is set equal to the number " + "of nodes. You only really need to set this if you are working with a very large system and " + "memory is at a premium"); } DFSClustering::DFSClustering(const ActionOptions&ao): -Action(ao), -ClusteringBase(ao) + Action(ao), + ClusteringBase(ao) { - unsigned maxconnections; parse("MAXCONNECT",maxconnections); -#ifdef __PLUMED_HAS_BOOST_GRAPH - if( maxconnections>0 ) edge_list.resize( getNumberOfNodes()*maxconnections ); - else edge_list.resize(0.5*getNumberOfNodes()*(getNumberOfNodes()-1)); + unsigned maxconnections; parse("MAXCONNECT",maxconnections); +#ifdef __PLUMED_HAS_BOOST_GRAPH + if( maxconnections>0 ) edge_list.resize( getNumberOfNodes()*maxconnections ); + else edge_list.resize(0.5*getNumberOfNodes()*(getNumberOfNodes()-1)); #else - nneigh.resize( getNumberOfNodes() ); color.resize(getNumberOfNodes()); - if( maxconnections>0 ) adj_list.resize(getNumberOfNodes(),maxconnections); - else adj_list.resize(getNumberOfNodes(),getNumberOfNodes()); + nneigh.resize( getNumberOfNodes() ); color.resize(getNumberOfNodes()); + if( maxconnections>0 ) adj_list.resize(getNumberOfNodes(),maxconnections); + else adj_list.resize(getNumberOfNodes(),getNumberOfNodes()); #endif } -void DFSClustering::performClustering(){ +void DFSClustering::performClustering() { #ifdef __PLUMED_HAS_BOOST_GRAPH - // Get the list of edges - unsigned nedges=0; getAdjacencyVessel()->retrieveEdgeList( nedges, edge_list ); + // Get the list of edges + unsigned nedges=0; getAdjacencyVessel()->retrieveEdgeList( nedges, edge_list ); - // Build the graph using boost - boost::adjacency_list<boost::vecS,boost::vecS,boost::undirectedS> sg(&edge_list[0],&edge_list[nedges],getNumberOfNodes()); + // Build the graph using boost + boost::adjacency_list<boost::vecS,boost::vecS,boost::undirectedS> sg(&edge_list[0],&edge_list[nedges],getNumberOfNodes()); - // Find the connected components using boost (-1 here for compatibility with non-boost version) - number_of_cluster=boost::connected_components(sg,&which_cluster[0]) - 1; + // Find the connected components using boost (-1 here for compatibility with non-boost version) + number_of_cluster=boost::connected_components(sg,&which_cluster[0]) - 1; - // And work out the size of each cluster - for(unsigned i=0;i<which_cluster.size();++i) cluster_sizes[which_cluster[i]].first++; + // And work out the size of each cluster + for(unsigned i=0; i<which_cluster.size(); ++i) cluster_sizes[which_cluster[i]].first++; #else - // Get the adjacency matrix - getAdjacencyVessel()->retrieveAdjacencyLists( nneigh, adj_list ); - - // Perform clustering - number_of_cluster=-1; color.assign(color.size(),0); - for(unsigned i=0;i<getNumberOfNodes();++i){ - if( color[i]==0 ){ number_of_cluster++; color[i]=explore(i); } - } + // Get the adjacency matrix + getAdjacencyVessel()->retrieveAdjacencyLists( nneigh, adj_list ); + + // Perform clustering + number_of_cluster=-1; color.assign(color.size(),0); + for(unsigned i=0; i<getNumberOfNodes(); ++i) { + if( color[i]==0 ) { number_of_cluster++; color[i]=explore(i); } + } #endif } #ifndef __PLUMED_HAS_BOOST_GRAPH -int DFSClustering::explore( const unsigned& index ){ - - color[index]=1; - for(unsigned i=0;i<nneigh[index];++i){ - unsigned j=adj_list(index,i); - if( color[j]==0 ) color[j]=explore(j); - } - - // Count the size of the cluster - cluster_sizes[number_of_cluster].first++; - which_cluster[index] = number_of_cluster; - return color[index]; +int DFSClustering::explore( const unsigned& index ) { + + color[index]=1; + for(unsigned i=0; i<nneigh[index]; ++i) { + unsigned j=adj_list(index,i); + if( color[j]==0 ) color[j]=explore(j); + } + + // Count the size of the cluster + cluster_sizes[number_of_cluster].first++; + which_cluster[index] = number_of_cluster; + return color[index]; } #endif diff --git a/src/adjmat/DumpGraph.cpp b/src/adjmat/DumpGraph.cpp index d243d09bf..3165de79c 100644 --- a/src/adjmat/DumpGraph.cpp +++ b/src/adjmat/DumpGraph.cpp @@ -52,61 +52,61 @@ public: /// Create manual static void registerKeywords( Keywords& keys ); /// Constructor - explicit DumpGraph( const ActionOptions& ); + explicit DumpGraph( const ActionOptions& ); /// Calculate and apply do nothing - void calculate(){}; - void apply(){}; + void calculate() {}; + void apply() {}; /// Update will do the output void update(); }; PLUMED_REGISTER_ACTION(DumpGraph,"DUMPGRAPH") -void DumpGraph::registerKeywords( Keywords& keys ){ +void DumpGraph::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionPilot::registerKeywords( keys ); keys.add("compulsory","MATRIX","the action that calcualtes the adjacency matrix vessel we would like to analyse"); keys.add("compulsory","STRIDE","1","the frequency with which you would like to output the graph"); keys.add("compulsory","FILE","the name of the file on which to output the data"); keys.add("compulsory","MAXCONNECT","0","maximum number of connections that can be formed by any given node in the graph. " - "By default this is set equal to zero and the number of connections is set equal to the number " - "of nodes. You only really need to set this if you are working with a very large system and " - "memory is at a premium"); + "By default this is set equal to zero and the number of connections is set equal to the number " + "of nodes. You only really need to set this if you are working with a very large system and " + "memory is at a premium"); } DumpGraph::DumpGraph( const ActionOptions& ao): -Action(ao), -ActionPilot(ao), -mymatrix(NULL) + Action(ao), + ActionPilot(ao), + mymatrix(NULL) { - parse("MAXCONNECT",maxconnections); std::string mstring; parse("MATRIX",mstring); - AdjacencyMatrixBase* mm = plumed.getActionSet().selectWithLabel<AdjacencyMatrixBase*>( mstring ); - if( !mm ) error("found no action in set with label " + mstring + " that calculates matrix"); - log.printf(" printing graph for matrix calculated by action %s\n", mm->getLabel().c_str() ); - - // Retrieve the adjacency matrix of interest - for(unsigned i=0;i<mm->getNumberOfVessels();++i){ - mymatrix = dynamic_cast<AdjacencyMatrixVessel*>( mm->getPntrToVessel(i) ); - if( mymatrix ) break ; - } - if( !mymatrix ) error( mm->getLabel() + " does not calculate an adjacency matrix"); - if( !mymatrix->isSymmetric() ) error("input contact matrix must be symmetric"); - if( maxconnections==0 ) maxconnections=mymatrix->getNumberOfRows(); - parse("FILE",filename); - log.printf(" printing graph to file named %s \n",filename.c_str() ); - checkRead(); + parse("MAXCONNECT",maxconnections); std::string mstring; parse("MATRIX",mstring); + AdjacencyMatrixBase* mm = plumed.getActionSet().selectWithLabel<AdjacencyMatrixBase*>( mstring ); + if( !mm ) error("found no action in set with label " + mstring + " that calculates matrix"); + log.printf(" printing graph for matrix calculated by action %s\n", mm->getLabel().c_str() ); + + // Retrieve the adjacency matrix of interest + for(unsigned i=0; i<mm->getNumberOfVessels(); ++i) { + mymatrix = dynamic_cast<AdjacencyMatrixVessel*>( mm->getPntrToVessel(i) ); + if( mymatrix ) break ; + } + if( !mymatrix ) error( mm->getLabel() + " does not calculate an adjacency matrix"); + if( !mymatrix->isSymmetric() ) error("input contact matrix must be symmetric"); + if( maxconnections==0 ) maxconnections=mymatrix->getNumberOfRows(); + parse("FILE",filename); + log.printf(" printing graph to file named %s \n",filename.c_str() ); + checkRead(); } -void DumpGraph::update(){ - OFile ofile; ofile.link(*this); ofile.setBackupString("graph"); - ofile.open( filename ); ofile.printf("graph G { \n"); - // Print all nodes - for(unsigned i=0;i<mymatrix->getNumberOfRows();++i) ofile.printf("%u [label=\"%u\"];\n",i,i); - // Now retrieve connectivitives - unsigned nedge; std::vector<std::pair<unsigned,unsigned> > edge_list( mymatrix->getNumberOfRows()*maxconnections ); - mymatrix->retrieveEdgeList( nedge, edge_list ); - for(unsigned i=0;i<nedge;++i) ofile.printf("%u -- %u \n", edge_list[i].first, edge_list[i].second ); - ofile.printf("} \n"); ofile.close(); +void DumpGraph::update() { + OFile ofile; ofile.link(*this); ofile.setBackupString("graph"); + ofile.open( filename ); ofile.printf("graph G { \n"); + // Print all nodes + for(unsigned i=0; i<mymatrix->getNumberOfRows(); ++i) ofile.printf("%u [label=\"%u\"];\n",i,i); + // Now retrieve connectivitives + unsigned nedge; std::vector<std::pair<unsigned,unsigned> > edge_list( mymatrix->getNumberOfRows()*maxconnections ); + mymatrix->retrieveEdgeList( nedge, edge_list ); + for(unsigned i=0; i<nedge; ++i) ofile.printf("%u -- %u \n", edge_list[i].first, edge_list[i].second ); + ofile.printf("} \n"); ofile.close(); } } diff --git a/src/adjmat/HbondMatrix.cpp b/src/adjmat/HbondMatrix.cpp index 82271fcd4..f75e95754 100644 --- a/src/adjmat/HbondMatrix.cpp +++ b/src/adjmat/HbondMatrix.cpp @@ -31,8 +31,8 @@ /* Adjacency matrix in which two atoms are adjacent if there is a hydrogen bond between them. -As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the -so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether +As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the +so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether or not the \f$i\f$th and \f$j\f$th atoms/molecules from a set of \f$N\f$ atoms/molecules are adjacent or not. These matrices can then be further analysed using a number of other algorithms as is detailed in \cite tribello-clustering. @@ -42,34 +42,34 @@ For this action the elements of the adjacency matrix are calculated using: a_{ij} = \sigma_{oo}( |\mathbf{r}_{ij}| ) \sum_{k=1}^N \sigma_{oh}( |\mathbf{r}_{ik}| ) \sigma_{\theta}( \theta_{kij} ) \f] -This expression was derived by thinking about how to detect if there is a hydrogen bond between atoms \f$i\f$ and \f$j\f$. The notion is that +This expression was derived by thinking about how to detect if there is a hydrogen bond between atoms \f$i\f$ and \f$j\f$. The notion is that if the hydrogen bond is present atoms \f$i\f$ and \f$j\f$ should be within a certain cutoff distance. In addition, there should be a hydrogen within a certain cutoff distance of atom \f$i\f$ and this hydrogen should lie on or close to the vector connecting atoms \f$i\f$ and \f$j\f$. -As such \f$\sigma_{oo}( |\mathbf{r}_{ij}| )\f$ is a \ref switchingfunction that acts on the modulus of the vector connecting atom \f$i\f$ to atom +As such \f$\sigma_{oo}( |\mathbf{r}_{ij}| )\f$ is a \ref switchingfunction that acts on the modulus of the vector connecting atom \f$i\f$ to atom \f$j\f$. The sum over \f$k\f$ then runs over all the hydrogen atoms that are specified using using HYDROGEN keyword. \f$\sigma_{oh}( |\mathbf{r}_{ik}| )\f$ -is a \ref switchingfunction that acts on the modulus of the vector connecting atom \f$i\f$ to atom \f$k\f$ and \f$\sigma_{\theta}( \theta_{kij} )\f$ -is a \ref switchingfunction that acts on the angle between the vector connecting atoms \f$i\f$ and \f$j\f$ and the vector connecting atoms \f$i\f$ and +is a \ref switchingfunction that acts on the modulus of the vector connecting atom \f$i\f$ to atom \f$k\f$ and \f$\sigma_{\theta}( \theta_{kij} )\f$ +is a \ref switchingfunction that acts on the angle between the vector connecting atoms \f$i\f$ and \f$j\f$ and the vector connecting atoms \f$i\f$ and \f$k\f$. -It is important to note that hydrogen bonds, unlike regular bonds, are asymetric. In other words, the hydrogen atom does not sit at the -mid point between the two other atoms in this three-center bond. As a result of this adjacency matrices calculated using \ref HBOND_MATRIX are not -symmetric like those calculated by \ref CONTACT_MATRIX. One consequence of this fact is that the quantities found by performing \ref ROWSUMS and -\ref COLUMNSUMS on a square \ref HBOND_MATRIX are not the same as they would be if you performed \ref ROWSUMS and -\ref COLUMNSUMS on a square \ref CONTACT_MATRIX. +It is important to note that hydrogen bonds, unlike regular bonds, are asymetric. In other words, the hydrogen atom does not sit at the +mid point between the two other atoms in this three-center bond. As a result of this adjacency matrices calculated using \ref HBOND_MATRIX are not +symmetric like those calculated by \ref CONTACT_MATRIX. One consequence of this fact is that the quantities found by performing \ref ROWSUMS and +\ref COLUMNSUMS on a square \ref HBOND_MATRIX are not the same as they would be if you performed \ref ROWSUMS and +\ref COLUMNSUMS on a square \ref CONTACT_MATRIX. \par Examples -The following input can be used to analyse the number of hydrogen bonds each of the oxygen atoms in a box of water participates in. Each +The following input can be used to analyse the number of hydrogen bonds each of the oxygen atoms in a box of water participates in. Each water molecule can participate in a hydrogen bond in one of two ways. It can either donate its hydrogens to the neighbouring oxygen or it can accept a bond between the hydrogen of a neighboring water molecule and its own oxygen. The input below allows you to output information on the number of hydrogen bonds each of the water molecules donates and accepts. This information is output in two xyz files which each contain five columns of data. The first four of these columns are a label for the atom and the x, y and z position of the oxygen. The last column is then -the number of accepted/donated hydrogen bonds. +the number of accepted/donated hydrogen bonds. \verbatim mat: HBOND_MATRIX ATOMS=1-192:3 HYDROGENS=2-192:3,3-192:3 SWITCH={RATIONAL R_0=3.20} HSWITCH={RATIONAL R_0=2.30} ASWITCH={RATIONAL R_0=0.167pi} SUM -rsums: ROWSUMS MATRIX=mat MEAN -csums: COLUMNSUMS MATRIX=mat MEAN +rsums: ROWSUMS MATRIX=mat MEAN +csums: COLUMNSUMS MATRIX=mat MEAN DUMPMULTICOLVAR DATA=rsums FILE=donors.xyz DUMPMULTICOLVAR DATA=csums FILE=acceptors.x \endverbatim @@ -101,86 +101,86 @@ public: double compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ) const ; /// double calculateForThree( const unsigned& iat, const unsigned& ano, const unsigned& dno, const Vector& ood, - const double& ood_df , const double& ood_sw, multicolvar::AtomValuePack& myatoms ) const ; + const double& ood_df, const double& ood_sw, multicolvar::AtomValuePack& myatoms ) const ; }; PLUMED_REGISTER_ACTION(HBondMatrix,"HBOND_MATRIX") -void HBondMatrix::registerKeywords( Keywords& keys ){ +void HBondMatrix::registerKeywords( Keywords& keys ) { AdjacencyMatrixBase::registerKeywords( keys ); keys.add("atoms","ATOMS","The list of atoms which can be part of a hydrogen bond. When this command is used the set of atoms that can donate a " - "hydrogen bond is assumed to be the same as the set of atoms that can form hydrogen bonds. The atoms involved must be specified" - "as a list of labels of \\ref mcolv or labels of a \\ref multicolvarfunction actions. If you would just like to use " - "the atomic positions you can use a \\ref DENSITY command to specify a group of atoms. Specifying your atomic positions using labels of " - "other \\ref mcolv or \\ref multicolvarfunction commands is useful, however, as you can then exploit a much wider " - "variety of functions of the contact matrix as described in \\ref contactmatrix"); + "hydrogen bond is assumed to be the same as the set of atoms that can form hydrogen bonds. The atoms involved must be specified" + "as a list of labels of \\ref mcolv or labels of a \\ref multicolvarfunction actions. If you would just like to use " + "the atomic positions you can use a \\ref DENSITY command to specify a group of atoms. Specifying your atomic positions using labels of " + "other \\ref mcolv or \\ref multicolvarfunction commands is useful, however, as you can then exploit a much wider " + "variety of functions of the contact matrix as described in \\ref contactmatrix"); keys.add("atoms","HYDROGENS","The list of hydrogen atoms that can form part of a hydrogen bond. The atoms must be specified using a comma separated list, " - "an index range or by using a \\ref GROUP. A list of hydrogen atoms is always required even if you specify the other atoms using " - "DONORS and ACCEPTORS as described below."); + "an index range or by using a \\ref GROUP. A list of hydrogen atoms is always required even if you specify the other atoms using " + "DONORS and ACCEPTORS as described below."); keys.add("atoms-2","DONORS","The list of atoms which can donate a hydrogen bond. The atoms involved must be specified " - "as a list of labels of \\ref mcolv or labels of a \\ref multicolvarfunction actions. If you would just like to use " - "the atomic positions you can use a \\ref DENSITY command to specify a group of atoms. Specifying your atomic positions using labels of " - "other \\ref mcolv or \\ref multicolvarfunction commands is useful, however, as you can then exploit a much wider " - "variety of functions of the contact matrix as described in \\ref contactmatrix"); + "as a list of labels of \\ref mcolv or labels of a \\ref multicolvarfunction actions. If you would just like to use " + "the atomic positions you can use a \\ref DENSITY command to specify a group of atoms. Specifying your atomic positions using labels of " + "other \\ref mcolv or \\ref multicolvarfunction commands is useful, however, as you can then exploit a much wider " + "variety of functions of the contact matrix as described in \\ref contactmatrix"); keys.add("atoms-2","ACCEPTORS","The list of atoms which can accept a hydrogen bond. The atoms involved must be specified " - "as a list of labels of \\ref mcolv or labels of a \\ref multicolvarfunction actions. If you would just like to use " - "the atomic positions you can use a \\ref DENSITY command to specify a group of atoms. Specifying your atomic positions using labels of " - "other \\ref mcolv or \\ref multicolvarfunction commands is useful, however, as you can then exploit a much wider " - "variety of functions of the contact matrix as described in \\ref contactmatrix"); + "as a list of labels of \\ref mcolv or labels of a \\ref multicolvarfunction actions. If you would just like to use " + "the atomic positions you can use a \\ref DENSITY command to specify a group of atoms. Specifying your atomic positions using labels of " + "other \\ref mcolv or \\ref multicolvarfunction commands is useful, however, as you can then exploit a much wider " + "variety of functions of the contact matrix as described in \\ref contactmatrix"); keys.add("numbered","SWITCH","The \\ref switchingfunction that specifies how close a pair of atoms must be together for there to be a hydrogen bond between them"); keys.add("numbered","HSWITCH","The \\ref switchingfunction that specifies how close the hydrogen must be to the donor atom of the hydrogen bond for it to be " - "considered a hydrogen bond"); + "considered a hydrogen bond"); keys.add("numbered","ASWITCH","A \\ref switchingfunction that is used to specify what the angle between the vector connecting the donor atom to the acceptor atom and " - "the vector connecting the donor atom to the hydrogen must be in order for it considered to be a hydrogen bond"); + "the vector connecting the donor atom to the hydrogen must be in order for it considered to be a hydrogen bond"); keys.use("SUM"); } HBondMatrix::HBondMatrix( const ActionOptions& ao ): -Action(ao), -AdjacencyMatrixBase(ao) + Action(ao), + AdjacencyMatrixBase(ao) { readMaxThreeSpeciesMatrix( "ATOMS", "DONORS", "ACCEPTORS", "HYDROGENS", false ); unsigned nrows, ncols; retrieveTypeDimensions( nrows, ncols, ndonor_types ); - distanceOOSwitch.resize( nrows, ncols ); distanceOHSwitch.resize( nrows, ncols ); angleSwitch.resize( nrows, ncols ); + distanceOOSwitch.resize( nrows, ncols ); distanceOHSwitch.resize( nrows, ncols ); angleSwitch.resize( nrows, ncols ); parseConnectionDescriptions("SWITCH",false,ndonor_types); parseConnectionDescriptions("HSWITCH",false,ndonor_types); parseConnectionDescriptions("ASWITCH",false,ndonor_types); // Find the largest sf cutoff double sfmax=distanceOOSwitch(0,0).get_dmax(); - for(unsigned i=0;i<getNumberOfNodeTypes();++i){ - for(unsigned j=0;j<getNumberOfNodeTypes();++j){ - double tsf=distanceOOSwitch(i,j).get_dmax(); - if( tsf>sfmax ) sfmax=tsf; - } + for(unsigned i=0; i<getNumberOfNodeTypes(); ++i) { + for(unsigned j=0; j<getNumberOfNodeTypes(); ++j) { + double tsf=distanceOOSwitch(i,j).get_dmax(); + if( tsf>sfmax ) sfmax=tsf; + } } // Set the link cell cutoff setLinkCellCutoff( sfmax ); } -void HBondMatrix::setupConnector( const unsigned& id, const unsigned& i, const unsigned& j, const std::vector<std::string>& desc ){ +void HBondMatrix::setupConnector( const unsigned& id, const unsigned& i, const unsigned& j, const std::vector<std::string>& desc ) { plumed_assert( id<3 && desc.size()==1 ); - if( id==0 ){ - std::string errors; distanceOOSwitch(j,i).set(desc[0],errors); - if( errors.length()!=0 ) error("problem reading switching function description " + errors); - if( j!=i) distanceOOSwitch(i,j).set(desc[0],errors); - log.printf(" atoms of type %u and %u must be within %s\n",i+1,j+1,(distanceOOSwitch(i,j).description()).c_str() ); - } else if( id==1 ){ - std::string errors; distanceOHSwitch(j,i).set(desc[0],errors); - if( errors.length()!=0 ) error("problem reading switching function description " + errors); - if( j!=i) distanceOHSwitch(i,j).set(desc[0],errors); - log.printf(" for atoms of type %u and %u the OH distance must be less than %s \n",i+1,j+1,(distanceOHSwitch(i,j).description()).c_str() ); - } else if( id==2 ){ - std::string errors; angleSwitch(j,i).set(desc[0],errors); - if( errors.length()!=0 ) error("problem reading switching function description " + errors); - if( j!=i) angleSwitch(i,j).set(desc[0],errors); - log.printf(" for atoms of type %u and %u the OOH angle must be less than %s \n",i+1,j+1,(angleSwitch(i,j).description()).c_str() ); - } + if( id==0 ) { + std::string errors; distanceOOSwitch(j,i).set(desc[0],errors); + if( errors.length()!=0 ) error("problem reading switching function description " + errors); + if( j!=i) distanceOOSwitch(i,j).set(desc[0],errors); + log.printf(" atoms of type %u and %u must be within %s\n",i+1,j+1,(distanceOOSwitch(i,j).description()).c_str() ); + } else if( id==1 ) { + std::string errors; distanceOHSwitch(j,i).set(desc[0],errors); + if( errors.length()!=0 ) error("problem reading switching function description " + errors); + if( j!=i) distanceOHSwitch(i,j).set(desc[0],errors); + log.printf(" for atoms of type %u and %u the OH distance must be less than %s \n",i+1,j+1,(distanceOHSwitch(i,j).description()).c_str() ); + } else if( id==2 ) { + std::string errors; angleSwitch(j,i).set(desc[0],errors); + if( errors.length()!=0 ) error("problem reading switching function description " + errors); + if( j!=i) angleSwitch(i,j).set(desc[0],errors); + log.printf(" for atoms of type %u and %u the OOH angle must be less than %s \n",i+1,j+1,(angleSwitch(i,j).description()).c_str() ); + } } double HBondMatrix::calculateWeight( const unsigned& taskCode, const double& weight, multicolvar::AtomValuePack& myatoms ) const { // Ensure we skip diagonal elements of square matrix - if( myatoms.getIndex(0)==myatoms.getIndex(1) ) return 0.0; + if( myatoms.getIndex(0)==myatoms.getIndex(1) ) return 0.0; Vector distance = getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); if( distance.modulo2()<distanceOOSwitch( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) ).get_dmax2() ) return 1.0; @@ -198,17 +198,17 @@ double HBondMatrix::compute( const unsigned& tindex, multicolvar::AtomValuePack& else ano = getBaseColvarNumber( myatoms.getIndex(1) ) - ndonor_types; double value=0; - if( myatoms.getNumberOfAtoms()>3 ){ - for(unsigned i=2;i<myatoms.getNumberOfAtoms();++i) value+=calculateForThree( i, ano, dno, ood, ood_df, ood_sw, myatoms ); + if( myatoms.getNumberOfAtoms()>3 ) { + for(unsigned i=2; i<myatoms.getNumberOfAtoms(); ++i) value+=calculateForThree( i, ano, dno, ood, ood_df, ood_sw, myatoms ); } else { - plumed_dbg_assert( myatoms.getNumberOfAtoms()==3 ); - value=calculateForThree( 2, ano, dno, ood, ood_df, ood_sw, myatoms ); + plumed_dbg_assert( myatoms.getNumberOfAtoms()==3 ); + value=calculateForThree( 2, ano, dno, ood, ood_df, ood_sw, myatoms ); } return value; } double HBondMatrix::calculateForThree( const unsigned& iat, const unsigned& ano, const unsigned& dno, const Vector& ood, - const double& ood_df , const double& ood_sw, multicolvar::AtomValuePack& myatoms ) const { + const double& ood_df, const double& ood_sw, multicolvar::AtomValuePack& myatoms ) const { Vector ohd=getSeparation( myatoms.getPosition(0), myatoms.getPosition(iat) ); double ohd_l=ohd.modulo(); double ohd_df, ohd_sw=distanceOHSwitch( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) ).calculate( ohd_l, ohd_df ); @@ -217,12 +217,12 @@ double HBondMatrix::calculateForThree( const unsigned& iat, const unsigned& ano, double angle_df, angle_sw=angleSwitch( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) ).calculate( angle, angle_df ); - if( !doNotCalculateDerivatives() ){ - addAtomDerivatives( 1, 0, angle_sw*ohd_sw*(-ood_df)*ood + angle_sw*ood_sw*(-ohd_df)*ohd + ood_sw*ohd_sw*angle_df*angle*(-ood_adf-ohd_adf), myatoms ); - addAtomDerivatives( 1, 1, angle_sw*ohd_sw*(+ood_df)*ood + ood_sw*ohd_sw*angle_df*angle*ood_adf, myatoms ); - addAtomDerivatives( 1, iat, angle_sw*ood_sw*(+ohd_df)*ohd + ood_sw*ohd_sw*angle_df*angle*ohd_adf, myatoms ); - myatoms.addBoxDerivatives( 1, angle_sw*ohd_sw*(-ood_df)*Tensor(ood,ood) + angle_sw*ood_sw*(-ohd_df)*Tensor(ohd,ohd) - -ood_sw*ohd_sw*angle_df*angle*(Tensor(ood,ood_adf)+Tensor(ohd,ohd_adf)) ); + if( !doNotCalculateDerivatives() ) { + addAtomDerivatives( 1, 0, angle_sw*ohd_sw*(-ood_df)*ood + angle_sw*ood_sw*(-ohd_df)*ohd + ood_sw*ohd_sw*angle_df*angle*(-ood_adf-ohd_adf), myatoms ); + addAtomDerivatives( 1, 1, angle_sw*ohd_sw*(+ood_df)*ood + ood_sw*ohd_sw*angle_df*angle*ood_adf, myatoms ); + addAtomDerivatives( 1, iat, angle_sw*ood_sw*(+ohd_df)*ohd + ood_sw*ohd_sw*angle_df*angle*ohd_adf, myatoms ); + myatoms.addBoxDerivatives( 1, angle_sw*ohd_sw*(-ood_df)*Tensor(ood,ood) + angle_sw*ood_sw*(-ohd_df)*Tensor(ohd,ohd) + -ood_sw*ohd_sw*angle_df*angle*(Tensor(ood,ood_adf)+Tensor(ohd,ohd_adf)) ); } return ood_sw*ohd_sw*angle_sw; } diff --git a/src/adjmat/MatrixColumnSums.cpp b/src/adjmat/MatrixColumnSums.cpp index ef7386b02..773502349 100644 --- a/src/adjmat/MatrixColumnSums.cpp +++ b/src/adjmat/MatrixColumnSums.cpp @@ -31,32 +31,32 @@ /* Sum the columns of a contact matrix -As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the -so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether -or not the \f$i\f$th and \f$j\f$th atoms/molecules from a set of \f$N\f$ atoms/molecules are adjacent or not. This action allows you to calculate +As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the +so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether +or not the \f$i\f$th and \f$j\f$th atoms/molecules from a set of \f$N\f$ atoms/molecules are adjacent or not. This action allows you to calculate the sum of the columns in this adjacency matrix and to then calculate further functions of these quantities. \par Examples The first instruction in the following input file tells PLUMED to compute a \f$10 \times 10\f$ matrix in which the \f$ij\f$-element tells you whether atoms \f$i\f$ and \f$j\f$ are within 1.0 nm of each other. The numbers in each of this rows are then added together -and the average value is computed. As such the following input provides an alternative method for calculating the coordination numbers -of atoms 1 to 10. +and the average value is computed. As such the following input provides an alternative method for calculating the coordination numbers +of atoms 1 to 10. \verbatim -mat: CONTACT_MATRIX ATOMS=1-10 SWITCH={RATIONAL R_0=1.0} -rsums: COLUMNSUMS MATRIX=mat MEAN -PRINT ARG=rsums.* FILE=colvar +mat: CONTACT_MATRIX ATOMS=1-10 SWITCH={RATIONAL R_0=1.0} +rsums: COLUMNSUMS MATRIX=mat MEAN +PRINT ARG=rsums.* FILE=colvar \endverbatim -The following input demonstrates another way that an average coordination number can be computed. This input calculates the number of atoms +The following input demonstrates another way that an average coordination number can be computed. This input calculates the number of atoms with indices between 1 and 5 that are within the first coordination spheres of each of the atoms within indices between 6 and 15. The average coordination number is then calculated from these fifteen coordination numbers and this quantity is output to a file. \verbatim -mat2: CONTACT_MATRIX ATOMSA=1-5 ATOMSB=6-15 SWITCH={RATIONAL R_0=1.0} -rsums: COLUMNSUMS MATRIX=mat2 MEAN -PRINT ARG=rsums.* FILE=colvar +mat2: CONTACT_MATRIX ATOMSA=1-5 ATOMSB=6-15 SWITCH={RATIONAL R_0=1.0} +rsums: COLUMNSUMS MATRIX=mat2 MEAN +PRINT ARG=rsums.* FILE=colvar \endverbatim */ @@ -69,12 +69,12 @@ class MatrixColumnSums : public ActionWithInputMatrix { public: static void registerKeywords( Keywords& keys ); explicit MatrixColumnSums(const ActionOptions&); - double compute( const unsigned& tinded, multicolvar::AtomValuePack& myatoms ) const ; + double compute( const unsigned& tinded, multicolvar::AtomValuePack& myatoms ) const ; }; PLUMED_REGISTER_ACTION(MatrixColumnSums,"COLUMNSUMS") -void MatrixColumnSums::registerKeywords( Keywords& keys ){ +void MatrixColumnSums::registerKeywords( Keywords& keys ) { ActionWithInputMatrix::registerKeywords( keys ); keys.use("ALT_MIN"); keys.use("LOWEST"); keys.use("HIGHEST"); keys.use("MEAN"); keys.use("MEAN"); keys.use("MIN"); keys.use("MAX"); keys.use("LESS_THAN"); @@ -82,38 +82,38 @@ void MatrixColumnSums::registerKeywords( Keywords& keys ){ } MatrixColumnSums::MatrixColumnSums(const ActionOptions& ao): -Action(ao), -ActionWithInputMatrix(ao) + Action(ao), + ActionWithInputMatrix(ao) { if( (mymatrix->getMatrixAction())->mybasemulticolvars.size()>0 ) error("matrix row sums should only be calculated when inputs are atoms"); // Setup the tasks - unsigned ncols = mymatrix->getNumberOfColumns(); + unsigned ncols = mymatrix->getNumberOfColumns(); ablocks.resize(1); ablocks[0].resize( ncols ); - for(unsigned i=0;i<ncols;++i) addTaskToList( i ); + for(unsigned i=0; i<ncols; ++i) addTaskToList( i ); // Set the positions - this is only used when getting positions for central atoms - if( mymatrix->undirectedGraph() ){ - for(unsigned i=0;i<ncols;++i) ablocks[0][i]=i; + if( mymatrix->undirectedGraph() ) { + for(unsigned i=0; i<ncols; ++i) ablocks[0][i]=i; } else { - for(unsigned i=0;i<ncols;++i) ablocks[0][i]=mymatrix->getNumberOfRows() + i; + for(unsigned i=0; i<ncols; ++i) ablocks[0][i]=mymatrix->getNumberOfRows() + i; } std::vector<AtomNumber> fake_atoms; setupMultiColvarBase( fake_atoms ); } double MatrixColumnSums::compute( const unsigned& tinded, multicolvar::AtomValuePack& myatoms ) const { double sum=0.0; std::vector<double> tvals( mymatrix->getNumberOfComponents() ); - unsigned nrows = mymatrix->getNumberOfRows(); - for(unsigned i=0;i<nrows;++i){ - if( mymatrix->undirectedGraph() && tinded==i ) continue; - sum+=retrieveConnectionValue( i, tinded, tvals ); + unsigned nrows = mymatrix->getNumberOfRows(); + for(unsigned i=0; i<nrows; ++i) { + if( mymatrix->undirectedGraph() && tinded==i ) continue; + sum+=retrieveConnectionValue( i, tinded, tvals ); } - if( !doNotCalculateDerivatives() ){ - MultiValue myvals( mymatrix->getNumberOfComponents(), myatoms.getNumberOfDerivatives() ); - MultiValue& myvout=myatoms.getUnderlyingMultiValue(); - for(unsigned i=0;i<nrows;++i){ - if( mymatrix->isSymmetric() && tinded==i ) continue ; - addConnectionDerivatives( i, tinded, myvals, myvout ); - } + if( !doNotCalculateDerivatives() ) { + MultiValue myvals( mymatrix->getNumberOfComponents(), myatoms.getNumberOfDerivatives() ); + MultiValue& myvout=myatoms.getUnderlyingMultiValue(); + for(unsigned i=0; i<nrows; ++i) { + if( mymatrix->isSymmetric() && tinded==i ) continue ; + addConnectionDerivatives( i, tinded, myvals, myvout ); + } } return sum; } diff --git a/src/adjmat/MatrixRowSums.cpp b/src/adjmat/MatrixRowSums.cpp index 1b7da9cf0..038aa89a7 100644 --- a/src/adjmat/MatrixRowSums.cpp +++ b/src/adjmat/MatrixRowSums.cpp @@ -27,36 +27,36 @@ #include "core/PlumedMain.h" #include "core/ActionSet.h" -//+PLUMEDOC MATRIXF ROWSUMS +//+PLUMEDOC MATRIXF ROWSUMS /* Sum the rows of a adjacency matrix. -As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the -so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether -or not the \f$i\f$th and \f$j\f$th atoms/molecules from a set of \f$N\f$ atoms/molecules are adjacent or not. This action allows you to calculate +As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the +so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether +or not the \f$i\f$th and \f$j\f$th atoms/molecules from a set of \f$N\f$ atoms/molecules are adjacent or not. This action allows you to calculate the sum of the rows in this adjacency matrix and to then calculate further functions of these quantities. \par Examples The first instruction in the following input file tells PLUMED to compute a \f$10 \times 10\f$ matrix in which the \f$ij\f$-element tells you whether atoms \f$i\f$ and \f$j\f$ are within 1.0 nm of each other. The numbers in each of this rows are then added together -and the average value is computed. As such the following input provides an alternative method for calculating the coordination numbers -of atoms 1 to 10. +and the average value is computed. As such the following input provides an alternative method for calculating the coordination numbers +of atoms 1 to 10. \verbatim -mat: CONTACT_MATRIX ATOMS=1-10 SWITCH={RATIONAL R_0=1.0} -rsums: ROWSUMS MATRIX=mat MEAN -PRINT ARG=rsums.* FILE=colvar +mat: CONTACT_MATRIX ATOMS=1-10 SWITCH={RATIONAL R_0=1.0} +rsums: ROWSUMS MATRIX=mat MEAN +PRINT ARG=rsums.* FILE=colvar \endverbatim -The following input demonstrates another way that an average coordination number can be computed. This input calculates the number of atoms +The following input demonstrates another way that an average coordination number can be computed. This input calculates the number of atoms with indices between 6 and 15 that are within the first coordination spheres of each of the atoms within indices between 1 and 5. The average coordination number is then calculated from these five coordination numbers and this quantity is output to a file. \verbatim -mat2: CONTACT_MATRIX ATOMSA=1-5 ATOMSB=6-15 SWITCH={RATIONAL R_0=1.0} -rsums: ROWSUMS MATRIX=mat2 MEAN -PRINT ARG=rsums.* FILE=colvar +mat2: CONTACT_MATRIX ATOMSA=1-5 ATOMSB=6-15 SWITCH={RATIONAL R_0=1.0} +rsums: ROWSUMS MATRIX=mat2 MEAN +PRINT ARG=rsums.* FILE=colvar \endverbatim */ @@ -69,12 +69,12 @@ class MatrixRowSums : public ActionWithInputMatrix { public: static void registerKeywords( Keywords& keys ); explicit MatrixRowSums(const ActionOptions&); - double compute( const unsigned& tinded, multicolvar::AtomValuePack& myatoms ) const ; + double compute( const unsigned& tinded, multicolvar::AtomValuePack& myatoms ) const ; }; PLUMED_REGISTER_ACTION(MatrixRowSums,"ROWSUMS") -void MatrixRowSums::registerKeywords( Keywords& keys ){ +void MatrixRowSums::registerKeywords( Keywords& keys ) { ActionWithInputMatrix::registerKeywords( keys ); keys.use("ALT_MIN"); keys.use("LOWEST"); keys.use("HIGHEST"); keys.use("MEAN"); keys.use("MEAN"); keys.use("MIN"); keys.use("MAX"); keys.use("LESS_THAN"); @@ -82,24 +82,24 @@ void MatrixRowSums::registerKeywords( Keywords& keys ){ } MatrixRowSums::MatrixRowSums(const ActionOptions& ao): -Action(ao), -ActionWithInputMatrix(ao) + Action(ao), + ActionWithInputMatrix(ao) { if( (mymatrix->getMatrixAction())->mybasemulticolvars.size()>0 ) error("matrix row sums should only be calculated when inputs are atoms"); // Setup the tasks - unsigned nrows = mymatrix->getNumberOfRows(); + unsigned nrows = mymatrix->getNumberOfRows(); ablocks.resize(1); ablocks[0].resize( nrows ); - for(unsigned i=0;i<nrows;++i){ ablocks[0][i]=i; addTaskToList( i ); } + for(unsigned i=0; i<nrows; ++i) { ablocks[0][i]=i; addTaskToList( i ); } std::vector<AtomNumber> fake_atoms; setupMultiColvarBase( fake_atoms ); } double MatrixRowSums::compute( const unsigned& tinded, multicolvar::AtomValuePack& myatoms ) const { - std::vector<double> tvals( mymatrix->getNumberOfComponents() ); + std::vector<double> tvals( mymatrix->getNumberOfComponents() ); getInputData( tinded, false, myatoms, tvals ); double fval=tvals[1]; - if( !doNotCalculateDerivatives() ){ - tvals.assign( tvals.size(), 0 ); tvals[1]=1.0; - mergeInputDerivatives( 1, 1, 2, tinded, tvals, getInputDerivatives( tinded, false, myatoms ), myatoms ); + if( !doNotCalculateDerivatives() ) { + tvals.assign( tvals.size(), 0 ); tvals[1]=1.0; + mergeInputDerivatives( 1, 1, 2, tinded, tvals, getInputDerivatives( tinded, false, myatoms ), myatoms ); } return fval; } diff --git a/src/adjmat/OutputCluster.cpp b/src/adjmat/OutputCluster.cpp index d4bba925b..c2b752f0d 100644 --- a/src/adjmat/OutputCluster.cpp +++ b/src/adjmat/OutputCluster.cpp @@ -36,16 +36,16 @@ The output in question here is either - a file that contains a list of the atom indices that form part of one of the clusters that was identified using \ref DFSCLUSTERING - an xyz file containing the positions of the atoms in one of the the clusters that was identified using \ref DFSCLUSTERING -Notice also that if you choose to output an xyz file you can ask PLUMED to try to reconstruct the cluster +Notice also that if you choose to output an xyz file you can ask PLUMED to try to reconstruct the cluster taking the periodic boundary conditions into account by using the MAKE_WHOLE flag. \par Examples -The input shown below identifies those atoms with a coordination number less than 13 +The input shown below identifies those atoms with a coordination number less than 13 and then constructs a contact matrix that describes the connectivity between the atoms -that satisfy this criteria. The DFS algorithm is then used to find the connected components +that satisfy this criteria. The DFS algorithm is then used to find the connected components in this matrix and the indices of the atoms in the largest connected component are then output -to a file. +to a file. \verbatim c1: COORDINATIONNUMBER SPECIES=1-1996 SWITCH={CUBIC D_0=0.34 D_MAX=0.38} @@ -81,14 +81,14 @@ private: public: static void registerKeywords( Keywords& keys ); explicit OutputCluster(const ActionOptions&); - void calculate(){} - void apply(){} + void calculate() {} + void apply() {} void update(); }; PLUMED_REGISTER_ACTION(OutputCluster,"OUTPUT_CLUSTER") -void OutputCluster::registerKeywords( Keywords& keys ){ +void OutputCluster::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionPilot::registerKeywords( keys ); keys.add("compulsory","CLUSTERS","the action that performed the clustering"); @@ -101,125 +101,125 @@ void OutputCluster::registerKeywords( Keywords& keys ){ } OutputCluster::OutputCluster(const ActionOptions& ao): -Action(ao), -ActionPilot(ao), -myclusters(NULL) + Action(ao), + ActionPilot(ao), + myclusters(NULL) { // Setup output file ofile.link(*this); std::string file; parse("FILE",file); if( file.length()==0 ) error("output file name was not specified"); // Search for xyz extension output_xyz=false; - if( file.find(".")!=std::string::npos ){ - std::size_t dot=file.find_first_of('.'); - if( file.substr(dot+1)=="xyz" ) output_xyz=true; + if( file.find(".")!=std::string::npos ) { + std::size_t dot=file.find_first_of('.'); + if( file.substr(dot+1)=="xyz" ) output_xyz=true; } - ofile.open(file); log.printf(" on file %s \n",file.c_str()); + ofile.open(file); log.printf(" on file %s \n",file.c_str()); parseFlag("MAKE_WHOLE",makewhole); parse("MAXDEPTH",maxdepth); parse("MAXGOES",maxgoes); if( makewhole && !output_xyz) error("MAKE_WHOLE flag is not compatible with output of non-xyz files"); // Find what action we are taking the clusters from std::vector<std::string> matname(1); parse("CLUSTERS",matname[0]); myclusters = plumed.getActionSet().selectWithLabel<ClusteringBase*>( matname[0] ); - if( !myclusters ) error( matname[0] + " does not calculate perform a clustering of the atomic positions"); + if( !myclusters ) error( matname[0] + " does not calculate perform a clustering of the atomic positions"); // N.B. the +0.3 is a fudge factor. Reconstrucing PBC doesnt work without this GAT addDependency( myclusters ); double rcut=myclusters->getCutoffForConnection() + 0.3; rcut2=rcut*rcut; // Read in the cluster we are calculating - parse("CLUSTER",clustr); + parse("CLUSTER",clustr); if( clustr<1 ) error("cannot look for a cluster larger than the largest cluster"); if( clustr>myclusters->getNumberOfNodes() ) error("cluster selected is invalid - too few atoms in system"); log.printf(" outputting atoms in %u th largest cluster found by %s \n",clustr,matname[0].c_str() ); } -void OutputCluster::update(){ +void OutputCluster::update() { myclusters->retrieveAtomsInCluster( clustr, myatoms ); - if( output_xyz ){ - ofile.printf("%u \n",static_cast<unsigned>(myatoms.size())); - ofile.printf("atoms in %u th largest cluster \n",clustr ); - if( makewhole ){ - // Retrieve the atom positions - atomsin.resize( myatoms.size() ); - for(unsigned i=0;i<myatoms.size();++i) atomsin[i]=myclusters->getPositionOfAtomForLinkCells( myatoms[i] ); - // Build a connectivity matrix neglecting the pbc - nneigh.resize( myatoms.size(), 0 ); adj_list.resize( myatoms.size(), myatoms.size() ); - for(unsigned i=1;i<myatoms.size();++i){ - for(unsigned j=0;j<i;++j){ - if( delta( atomsin[i], atomsin[j] ).modulo2()<=rcut2 ){ adj_list(i,nneigh[i])=j; adj_list(j,nneigh[j])=i; nneigh[i]++; nneigh[j]++; } - } + if( output_xyz ) { + ofile.printf("%u \n",static_cast<unsigned>(myatoms.size())); + ofile.printf("atoms in %u th largest cluster \n",clustr ); + if( makewhole ) { + // Retrieve the atom positions + atomsin.resize( myatoms.size() ); + for(unsigned i=0; i<myatoms.size(); ++i) atomsin[i]=myclusters->getPositionOfAtomForLinkCells( myatoms[i] ); + // Build a connectivity matrix neglecting the pbc + nneigh.resize( myatoms.size(), 0 ); adj_list.resize( myatoms.size(), myatoms.size() ); + for(unsigned i=1; i<myatoms.size(); ++i) { + for(unsigned j=0; j<i; ++j) { + if( delta( atomsin[i], atomsin[j] ).modulo2()<=rcut2 ) { adj_list(i,nneigh[i])=j; adj_list(j,nneigh[j])=i; nneigh[i]++; nneigh[j]++; } } - // Use DFS to find the largest cluster not broken by PBC - number_of_cluster=-1; visited.resize( myatoms.size(), false ); - cluster_sizes.resize( myatoms.size() ); which_cluster.resize( myatoms.size() ); - for(unsigned i=0;i<cluster_sizes.size();++i){ cluster_sizes[i].first=0; cluster_sizes[i].second=i; } - - for(unsigned i=0;i<myatoms.size();++i){ - if( !visited[i] ){ number_of_cluster++; visited[i]=explore_dfs(i); } + } + // Use DFS to find the largest cluster not broken by PBC + number_of_cluster=-1; visited.resize( myatoms.size(), false ); + cluster_sizes.resize( myatoms.size() ); which_cluster.resize( myatoms.size() ); + for(unsigned i=0; i<cluster_sizes.size(); ++i) { cluster_sizes[i].first=0; cluster_sizes[i].second=i; } + + for(unsigned i=0; i<myatoms.size(); ++i) { + if( !visited[i] ) { number_of_cluster++; visited[i]=explore_dfs(i); } + } + std::sort( cluster_sizes.begin(), cluster_sizes.end() ); + + // Now set visited so that only those atoms in largest cluster will be start points for PBCing + visited.assign( visited.size(), false ); + for(unsigned i=0; i<myatoms.size(); ++i) { + if( which_cluster[i]==cluster_sizes[cluster_sizes.size()-1].second ) visited[i]=true; + } + + // Now retrieve the original connectivity matrix (including pbc) + nneigh.assign( nneigh.size(), 0 ); + for(unsigned i=1; i<myatoms.size(); ++i) { + for(unsigned j=0; j<i; ++j) { + if( myclusters->areConnected( myatoms[i], myatoms[j] ) ) { adj_list(i,nneigh[i])=j; adj_list(j,nneigh[j])=i; nneigh[i]++; nneigh[j]++; } } - std::sort( cluster_sizes.begin(), cluster_sizes.end() ); + } - // Now set visited so that only those atoms in largest cluster will be start points for PBCing - visited.assign( visited.size(), false ); - for(unsigned i=0;i<myatoms.size();++i){ - if( which_cluster[i]==cluster_sizes[cluster_sizes.size()-1].second ) visited[i]=true; - } - - // Now retrieve the original connectivity matrix (including pbc) - nneigh.assign( nneigh.size(), 0 ); - for(unsigned i=1;i<myatoms.size();++i){ - for(unsigned j=0;j<i;++j){ - if( myclusters->areConnected( myatoms[i], myatoms[j] ) ){ adj_list(i,nneigh[i])=j; adj_list(j,nneigh[j])=i; nneigh[i]++; nneigh[j]++; } - } - } + // Now find broken bonds and run iterative deepening depth first search to reconstruct + for(unsigned jj=0; jj<maxgoes; ++jj) { - // Now find broken bonds and run iterative deepening depth first search to reconstruct - for(unsigned jj=0;jj<maxgoes;++jj){ + for(unsigned j=0; j<myatoms.size(); ++j) { + if( !visited[j] ) continue; - for(unsigned j=0;j<myatoms.size();++j){ - if( !visited[j] ) continue; - - for(unsigned k=0;k<nneigh[j];++k){ - if( delta( atomsin[j],atomsin[adj_list(j,k)] ).modulo2()>rcut2 ){ - visited[j]=true; - for(unsigned depth=0;depth<=maxdepth;++depth) explore( j, depth ); - } - } + for(unsigned k=0; k<nneigh[j]; ++k) { + if( delta( atomsin[j],atomsin[adj_list(j,k)] ).modulo2()>rcut2 ) { + visited[j]=true; + for(unsigned depth=0; depth<=maxdepth; ++depth) explore( j, depth ); } + } } - // And print final positions - for(unsigned i=0;i<myatoms.size();++i) ofile.printf( "X %f %f %f \n", atomsin[i][0], atomsin[i][1], atomsin[i][2] ); - } else { - for(unsigned i=0;i<myatoms.size();++i){ - Vector pos=myclusters->getPositionOfAtomForLinkCells( myatoms[i] ); - ofile.printf( "X %f %f %f \n", pos[0], pos[1], pos[2] ); - } - } + } + // And print final positions + for(unsigned i=0; i<myatoms.size(); ++i) ofile.printf( "X %f %f %f \n", atomsin[i][0], atomsin[i][1], atomsin[i][2] ); + } else { + for(unsigned i=0; i<myatoms.size(); ++i) { + Vector pos=myclusters->getPositionOfAtomForLinkCells( myatoms[i] ); + ofile.printf( "X %f %f %f \n", pos[0], pos[1], pos[2] ); + } + } } else { - ofile.printf("CLUSTERING RESULTS AT TIME %f : NUMBER OF ATOMS IN %u TH LARGEST CLUSTER EQUALS %u \n",getTime(),clustr,static_cast<unsigned>(myatoms.size()) ); - ofile.printf("INDICES OF ATOMS : "); - for(unsigned i=0;i<myatoms.size();++i) ofile.printf("%d ",(myclusters->getAbsoluteIndexOfCentralAtom(myatoms[i])).index()); - ofile.printf("\n"); + ofile.printf("CLUSTERING RESULTS AT TIME %f : NUMBER OF ATOMS IN %u TH LARGEST CLUSTER EQUALS %u \n",getTime(),clustr,static_cast<unsigned>(myatoms.size()) ); + ofile.printf("INDICES OF ATOMS : "); + for(unsigned i=0; i<myatoms.size(); ++i) ofile.printf("%d ",(myclusters->getAbsoluteIndexOfCentralAtom(myatoms[i])).index()); + ofile.printf("\n"); } } -void OutputCluster::explore( const unsigned& index, const unsigned& depth ){ +void OutputCluster::explore( const unsigned& index, const unsigned& depth ) { if( depth==0 ) return ; - for(unsigned i=0;i<nneigh[index];++i){ - unsigned j=adj_list(index,i); visited[j]=true; - Vector svec=myclusters->pbcDistance( atomsin[index], atomsin[j] ); - atomsin[j] = atomsin[index] + svec; - explore( j, depth-1 ); - } + for(unsigned i=0; i<nneigh[index]; ++i) { + unsigned j=adj_list(index,i); visited[j]=true; + Vector svec=myclusters->pbcDistance( atomsin[index], atomsin[j] ); + atomsin[j] = atomsin[index] + svec; + explore( j, depth-1 ); + } } -bool OutputCluster::explore_dfs( const unsigned& index ){ +bool OutputCluster::explore_dfs( const unsigned& index ) { visited[index]=true; - for(unsigned i=0;i<nneigh[index];++i){ - unsigned j=adj_list(index,i); - if( !visited[j] ) visited[j]=explore_dfs(j); - } + for(unsigned i=0; i<nneigh[index]; ++i) { + unsigned j=adj_list(index,i); + if( !visited[j] ) visited[j]=explore_dfs(j); + } // Count the size of the cluster cluster_sizes[number_of_cluster].first++; diff --git a/src/adjmat/SMACMatrix.cpp b/src/adjmat/SMACMatrix.cpp index 269be8043..ac433076b 100644 --- a/src/adjmat/SMACMatrix.cpp +++ b/src/adjmat/SMACMatrix.cpp @@ -25,28 +25,28 @@ #include "tools/Torsion.h" #include "tools/Matrix.h" -//+PLUMEDOC MATRIX SMAC_MATRIX +//+PLUMEDOC MATRIX SMAC_MATRIX /* Adjacency matrix in which two molecules are adjacent if they are within a certain cutoff and if the angle between them is within certain ranges. In this case the elements of the adjacency matrix are calculated using: \f[ -A_{ij} = \sigma(r_{ij}) \sum_n K_n(\theta_{ij}) +A_{ij} = \sigma(r_{ij}) \sum_n K_n(\theta_{ij}) \f] In this expression \f$r_{ij}\f$ is the distance between molecule \f$i\f$ and molecule \f$j\f$ and \f$\sigma(r_{ij}\f$ is a -\ref switchingfunction that acts on this distance. The $K_n functions are \ref kernelfunctions that take the torsion angle, \f$\theta_{ij}\f$, between the +\ref switchingfunction that acts on this distance. The $K_n functions are \ref kernelfunctions that take the torsion angle, \f$\theta_{ij}\f$, between the internal orientation vectors for molecules \f$i\f$ and \f$j\f$ as input. These kernel functions should be set so that they are equal to one when the relative orientation of the moleclues are as they are in the solid and equal to zero otherwise. As the above matrix element is a product of functions it is only equal to one when the centers of mass of molecules \f$i\f$ and\f$j\f$ -are with a certain distance of each other and when the molecules are aligned in some desirable way. +are with a certain distance of each other and when the molecules are aligned in some desirable way. \par Examples -In the following example an adjacency matrix is constructed in which the \f$(i,j)\f$ element is equal to one if -molecules \f$i\f$ and \f$j\f$ are within 6 angstroms of each other and if the torsional angle between the orientations -of these molecules is close to 0 or \f$\pi\f$. The various connected components of this matrix are determined using the +In the following example an adjacency matrix is constructed in which the \f$(i,j)\f$ element is equal to one if +molecules \f$i\f$ and \f$j\f$ are within 6 angstroms of each other and if the torsional angle between the orientations +of these molecules is close to 0 or \f$\pi\f$. The various connected components of this matrix are determined using the \ref DFSCLUSTERING algorithm and then the size of the largest cluster of connectes molecules is output to a colvar file \verbatim @@ -61,8 +61,8 @@ MOL5=17,18,17 LABEL=m1 ... MOLECULES -SMAC_MATRIX ... - ATOMS=m1 SWITCH={RATIONAL D_0=5.99 R_0=0.1 D_MAX=6.0} +SMAC_MATRIX ... + ATOMS=m1 SWITCH={RATIONAL D_0=5.99 R_0=0.1 D_MAX=6.0} KERNEL1={TRIANGULAR CENTER=0 SIGMA=1.0} KERNEL2={TRIANGULAR CENTER=pi SIGMA=0.6} LABEL=smacm ... SMAC_MATRIX @@ -80,67 +80,67 @@ namespace adjmat { class SMACMatrix : public AlignedMatrixBase { private: - Matrix<std::vector<KernelFunctions> > kernels; + Matrix<std::vector<KernelFunctions> > kernels; public: - /// - static void registerKeywords( Keywords& keys ); - /// - explicit SMACMatrix(const ActionOptions&); - void readOrientationConnector( const unsigned& i, const unsigned& j, const std::vector<std::string>& desc ); - double computeVectorFunction( const unsigned& iv, const unsigned& jv, - const Vector& conn, const std::vector<double>& vec1, const std::vector<double>& vec2, - Vector& dconn, std::vector<double>& dvec1, std::vector<double>& dvec2 ) const ; + /// + static void registerKeywords( Keywords& keys ); + /// + explicit SMACMatrix(const ActionOptions&); + void readOrientationConnector( const unsigned& i, const unsigned& j, const std::vector<std::string>& desc ); + double computeVectorFunction( const unsigned& iv, const unsigned& jv, + const Vector& conn, const std::vector<double>& vec1, const std::vector<double>& vec2, + Vector& dconn, std::vector<double>& dvec1, std::vector<double>& dvec2 ) const ; }; PLUMED_REGISTER_ACTION(SMACMatrix,"SMAC_MATRIX") -void SMACMatrix::registerKeywords( Keywords& keys ){ - AlignedMatrixBase::registerKeywords( keys ); - keys.add("numbered","KERNEL","The various kernels that are used to determine whether or not the molecules are aligned"); +void SMACMatrix::registerKeywords( Keywords& keys ) { + AlignedMatrixBase::registerKeywords( keys ); + keys.add("numbered","KERNEL","The various kernels that are used to determine whether or not the molecules are aligned"); } SMACMatrix::SMACMatrix( const ActionOptions& ao ): -Action(ao), -AlignedMatrixBase(ao) + Action(ao), + AlignedMatrixBase(ao) { - unsigned nrows, ncols, ig; retrieveTypeDimensions( nrows, ncols, ig ); - kernels.resize( nrows, ncols ); parseConnectionDescriptions("KERNEL",true,0); + unsigned nrows, ncols, ig; retrieveTypeDimensions( nrows, ncols, ig ); + kernels.resize( nrows, ncols ); parseConnectionDescriptions("KERNEL",true,0); } -void SMACMatrix::readOrientationConnector( const unsigned& iv, const unsigned& jv, const std::vector<std::string>& desc ){ - for(int i=0;i<desc.size();i++){ - KernelFunctions mykernel( desc[i], false ); - kernels(iv,jv).push_back( mykernel ); - if( jv!=iv ) kernels(jv,iv).push_back( mykernel ); - } - if( kernels(iv,jv).size()==0 ) error("no kernels defined"); +void SMACMatrix::readOrientationConnector( const unsigned& iv, const unsigned& jv, const std::vector<std::string>& desc ) { + for(int i=0; i<desc.size(); i++) { + KernelFunctions mykernel( desc[i], false ); + kernels(iv,jv).push_back( mykernel ); + if( jv!=iv ) kernels(jv,iv).push_back( mykernel ); + } + if( kernels(iv,jv).size()==0 ) error("no kernels defined"); } double SMACMatrix::computeVectorFunction( const unsigned& iv, const unsigned& jv, - const Vector& conn, const std::vector<double>& vec1, const std::vector<double>& vec2, - Vector& dconn, std::vector<double>& dvec1, std::vector<double>& dvec2 ) const { + const Vector& conn, const std::vector<double>& vec1, const std::vector<double>& vec2, + Vector& dconn, std::vector<double>& dvec1, std::vector<double>& dvec2 ) const { unsigned nvectors = ( vec1.size() - 2 ) / 3; plumed_assert( (vec1.size()-2)%3==0 ); std::vector<Vector> dv1(nvectors), dv2(nvectors), tdconn(nvectors); Torsion t; std::vector<Vector> v1(nvectors), v2(nvectors); - std::vector<Value*> pos; for(unsigned i=0;i<nvectors;++i){ pos.push_back( new Value() ); pos[i]->setDomain( "-pi", "pi" ); } - - for(unsigned j=0;j<nvectors;++j){ - for(unsigned k=0;k<3;++k){ - v1[j][k]=vec1[2+3*j+k]; v2[j][k]=vec2[2+3*j+k]; - } - double angle = t.compute( v1[j], conn, v2[j], dv1[j], tdconn[j], dv2[j] ); - pos[j]->set( angle ); + std::vector<Value*> pos; for(unsigned i=0; i<nvectors; ++i) { pos.push_back( new Value() ); pos[i]->setDomain( "-pi", "pi" ); } + + for(unsigned j=0; j<nvectors; ++j) { + for(unsigned k=0; k<3; ++k) { + v1[j][k]=vec1[2+3*j+k]; v2[j][k]=vec2[2+3*j+k]; + } + double angle = t.compute( v1[j], conn, v2[j], dv1[j], tdconn[j], dv2[j] ); + pos[j]->set( angle ); } - - double ans=0; std::vector<double> deriv( nvectors ), df( nvectors, 0 ); - for(unsigned i=0;i<kernels(iv,jv).size();++i){ - ans += kernels(iv,jv)[i].evaluate( pos, deriv ); - for(unsigned j=0;j<nvectors;++j) df[j] += deriv[j]; + + double ans=0; std::vector<double> deriv( nvectors ), df( nvectors, 0 ); + for(unsigned i=0; i<kernels(iv,jv).size(); ++i) { + ans += kernels(iv,jv)[i].evaluate( pos, deriv ); + for(unsigned j=0; j<nvectors; ++j) df[j] += deriv[j]; } - dconn.zero(); for(unsigned j=0;j<nvectors;++j) dconn += df[j]*tdconn[j]; - for(unsigned j=0;j<nvectors;++j){ - for(unsigned k=0;k<3;++k){ dvec1[2+3*j+k]=df[j]*dv1[j][k]; dvec2[2+3*j+k]=df[j]*dv2[j][k]; } - delete pos[j]; + dconn.zero(); for(unsigned j=0; j<nvectors; ++j) dconn += df[j]*tdconn[j]; + for(unsigned j=0; j<nvectors; ++j) { + for(unsigned k=0; k<3; ++k) { dvec1[2+3*j+k]=df[j]*dv1[j][k]; dvec2[2+3*j+k]=df[j]*dv2[j][k]; } + delete pos[j]; } return ans; } diff --git a/src/adjmat/Sprint.cpp b/src/adjmat/Sprint.cpp index 7ffdd74b9..f7e0a0da8 100644 --- a/src/adjmat/Sprint.cpp +++ b/src/adjmat/Sprint.cpp @@ -36,8 +36,8 @@ s_i = \sqrt{n} \lambda v_i You can use different quantities to measure whether or not two given atoms/molecules are adjacent or not in the adjacency matrix. The simplest measure of adjacency is is whether -two atoms/molecules are within some cutoff of each other. Further complexity can be added by -insisting that two molecules are adjacent if they are within a certain distance of each +two atoms/molecules are within some cutoff of each other. Further complexity can be added by +insisting that two molecules are adjacent if they are within a certain distance of each other and if they have similar orientations. \par Examples @@ -50,7 +50,7 @@ in the manner described in ?? so two atoms are adjacent if they are within a cut DENSITY SPECIES=1-7 LABEL=d1 CONTACT_MATRIX ATOMS=d1 SWITCH={RATIONAL R_0=0.1} LABEL=mat SPRINT MATRIX=mat LABEL=ss -PRINT ARG=ss.* FILE=colvar +PRINT ARG=ss.* FILE=colvar \endverbatim This example input calculates the 14 SPRINT coordinates foa a molecule composed of 7 hydrogen and @@ -68,7 +68,7 @@ CONTACT_MATRIX ... LABEL=mat ... CONTACT_MATRIX -SPRINT MATRIX=mat LABEL=ss +SPRINT MATRIX=mat LABEL=ss PRINT ARG=ss.* FILE=colvar \endverbatim @@ -107,133 +107,133 @@ public: PLUMED_REGISTER_ACTION(Sprint,"SPRINT") -void Sprint::registerKeywords( Keywords& keys ){ +void Sprint::registerKeywords( Keywords& keys ) { ActionWithInputMatrix::registerKeywords( keys ); componentsAreNotOptional(keys); keys.addOutputComponent("coord","default","all \\f$n\\f$ sprint coordinates are calculated and then stored in increasing order. " - "the smallest sprint coordinate will be labelled <em>label</em>.coord-1, " - "the second smallest will be labelleled <em>label</em>.coord-1 and so on"); + "the smallest sprint coordinate will be labelled <em>label</em>.coord-1, " + "the second smallest will be labelleled <em>label</em>.coord-1 and so on"); } Sprint::Sprint(const ActionOptions&ao): -Action(ao), -ActionWithInputMatrix(ao), -eigvals( getNumberOfNodes() ), -maxeig( getNumberOfNodes() ), -thematrix( getNumberOfNodes(), getNumberOfNodes() ), -eigenvecs( getNumberOfNodes(), getNumberOfNodes() ) + Action(ao), + ActionWithInputMatrix(ao), + eigvals( getNumberOfNodes() ), + maxeig( getNumberOfNodes() ), + thematrix( getNumberOfNodes(), getNumberOfNodes() ), + eigenvecs( getNumberOfNodes(), getNumberOfNodes() ) { - // Check on setup - // if( getNumberOfVessels()!=1 ) error("there should be no vessel keywords"); - // Check for bad colvar input ( we are going to get rid of this because we are going to have input adjacency matrix in future ) - // for(unsigned i=0;i<getNumberOfAtomGroups();++i){ - // /// Check me GAT - // // if( !getBaseMultiColvar(i)->hasDifferentiableOrientation() ) error("cannot use multicolvar of type " + getBaseMultiColvar(i)->getName() ); - // } - - if( !getAdjacencyVessel()->isSymmetric() ) error("input contact matrix is not symmetric"); - std::vector<AtomNumber> fake_atoms; setupMultiColvarBase( fake_atoms ); - - // Create all the values - sqrtn = sqrt( static_cast<double>( getNumberOfNodes() ) ); - for(unsigned i=0;i<getNumberOfNodes();++i){ - std::string num; Tools::convert(i,num); - addComponentWithDerivatives("coord-"+num); - componentIsNotPeriodic("coord-"+num); - getPntrToComponent(i)->resizeDerivatives( getNumberOfDerivatives() ); - } - - // Setup the dynamic list to hold all the tasks - unsigned ntriangle = 0.5*getNumberOfNodes()*(getNumberOfNodes()-1); - for(unsigned i=0;i<ntriangle;++i) active_elements.addIndexToList( i ); + // Check on setup + // if( getNumberOfVessels()!=1 ) error("there should be no vessel keywords"); + // Check for bad colvar input ( we are going to get rid of this because we are going to have input adjacency matrix in future ) + // for(unsigned i=0;i<getNumberOfAtomGroups();++i){ + // /// Check me GAT + // // if( !getBaseMultiColvar(i)->hasDifferentiableOrientation() ) error("cannot use multicolvar of type " + getBaseMultiColvar(i)->getName() ); + // } + + if( !getAdjacencyVessel()->isSymmetric() ) error("input contact matrix is not symmetric"); + std::vector<AtomNumber> fake_atoms; setupMultiColvarBase( fake_atoms ); + + // Create all the values + sqrtn = sqrt( static_cast<double>( getNumberOfNodes() ) ); + for(unsigned i=0; i<getNumberOfNodes(); ++i) { + std::string num; Tools::convert(i,num); + addComponentWithDerivatives("coord-"+num); + componentIsNotPeriodic("coord-"+num); + getPntrToComponent(i)->resizeDerivatives( getNumberOfDerivatives() ); + } + + // Setup the dynamic list to hold all the tasks + unsigned ntriangle = 0.5*getNumberOfNodes()*(getNumberOfNodes()-1); + for(unsigned i=0; i<ntriangle; ++i) active_elements.addIndexToList( i ); } -void Sprint::calculate(){ - // Get the adjacency matrix - getAdjacencyVessel()->retrieveMatrix( active_elements, thematrix ); - // Diagonalize it - diagMat( thematrix, eigvals, eigenvecs ); - // Get the maximum eigevalue - double lambda = eigvals[ getNumberOfNodes()-1 ]; - // Get the corresponding eigenvector - for(unsigned j=0;j<maxeig.size();++j){ - maxeig[j].first = fabs( eigenvecs( getNumberOfNodes()-1, j ) ); - maxeig[j].second = j; - // Must make all components of principle eigenvector +ve - eigenvecs( getNumberOfNodes()-1, j ) = maxeig[j].first; - } - - // Reorder each block of eigevectors - unsigned startnum=0; - for(unsigned j=0;j<getNumberOfNodeTypes();++j){ - unsigned nthis = getNumberOfAtomsInGroup(j); - // Sort into ascending order - std::sort( maxeig.begin() + startnum, maxeig.begin() + startnum + nthis ); - // Used so we can do sorting in blocks - startnum += nthis; - } - // Set the sprint coordinates - for(unsigned icomp=0;icomp<getNumberOfComponents();++icomp){ - getPntrToComponent(icomp)->set( sqrtn*lambda*maxeig[icomp].first ); - } - - // Parallelism - unsigned rank, stride; - if( serialCalculation() ){ stride=1; rank=0; } - else { rank=comm.Get_rank(); stride=comm.Get_size(); } - - // Derivatives - MultiValue myvals( 2, getNumberOfDerivatives() ); - Matrix<double> mymat_ders( getNumberOfComponents(), getNumberOfDerivatives() ); - // std::vector<unsigned> catoms(2); - unsigned nval = getNumberOfNodes(); mymat_ders=0; - for(unsigned i=rank;i<active_elements.getNumberActive();i+=stride){ - unsigned j, k; getAdjacencyVessel()->getMatrixIndices( active_elements[i], j, k ); - double tmp1 = 2 * eigenvecs(nval-1,j)*eigenvecs(nval-1,k); - for(unsigned icomp=0;icomp<getNumberOfComponents();++icomp){ - double tmp2 = 0.; - for(unsigned n=0;n<nval-1;++n){ // Need care on following line - tmp2 += eigenvecs(n,maxeig[icomp].second) * ( eigenvecs(n,j)*eigenvecs(nval-1,k) + eigenvecs(n,k)*eigenvecs(nval-1,j) ) / ( lambda - eigvals[n] ); - } - double prefactor=sqrtn*( tmp1*maxeig[icomp].first + tmp2*lambda ); - getAdjacencyVessel()->retrieveDerivatives( active_elements[i], false, myvals ); - for(unsigned jd=0;jd<myvals.getNumberActive();++jd){ - unsigned ider=myvals.getActiveIndex(jd); - mymat_ders( icomp, ider ) += prefactor*myvals.getDerivative( 1, ider ); - } +void Sprint::calculate() { + // Get the adjacency matrix + getAdjacencyVessel()->retrieveMatrix( active_elements, thematrix ); + // Diagonalize it + diagMat( thematrix, eigvals, eigenvecs ); + // Get the maximum eigevalue + double lambda = eigvals[ getNumberOfNodes()-1 ]; + // Get the corresponding eigenvector + for(unsigned j=0; j<maxeig.size(); ++j) { + maxeig[j].first = fabs( eigenvecs( getNumberOfNodes()-1, j ) ); + maxeig[j].second = j; + // Must make all components of principle eigenvector +ve + eigenvecs( getNumberOfNodes()-1, j ) = maxeig[j].first; + } + + // Reorder each block of eigevectors + unsigned startnum=0; + for(unsigned j=0; j<getNumberOfNodeTypes(); ++j) { + unsigned nthis = getNumberOfAtomsInGroup(j); + // Sort into ascending order + std::sort( maxeig.begin() + startnum, maxeig.begin() + startnum + nthis ); + // Used so we can do sorting in blocks + startnum += nthis; + } + // Set the sprint coordinates + for(unsigned icomp=0; icomp<getNumberOfComponents(); ++icomp) { + getPntrToComponent(icomp)->set( sqrtn*lambda*maxeig[icomp].first ); + } + + // Parallelism + unsigned rank, stride; + if( serialCalculation() ) { stride=1; rank=0; } + else { rank=comm.Get_rank(); stride=comm.Get_size(); } + + // Derivatives + MultiValue myvals( 2, getNumberOfDerivatives() ); + Matrix<double> mymat_ders( getNumberOfComponents(), getNumberOfDerivatives() ); + // std::vector<unsigned> catoms(2); + unsigned nval = getNumberOfNodes(); mymat_ders=0; + for(unsigned i=rank; i<active_elements.getNumberActive(); i+=stride) { + unsigned j, k; getAdjacencyVessel()->getMatrixIndices( active_elements[i], j, k ); + double tmp1 = 2 * eigenvecs(nval-1,j)*eigenvecs(nval-1,k); + for(unsigned icomp=0; icomp<getNumberOfComponents(); ++icomp) { + double tmp2 = 0.; + for(unsigned n=0; n<nval-1; ++n) { // Need care on following line + tmp2 += eigenvecs(n,maxeig[icomp].second) * ( eigenvecs(n,j)*eigenvecs(nval-1,k) + eigenvecs(n,k)*eigenvecs(nval-1,j) ) / ( lambda - eigvals[n] ); + } + double prefactor=sqrtn*( tmp1*maxeig[icomp].first + tmp2*lambda ); + getAdjacencyVessel()->retrieveDerivatives( active_elements[i], false, myvals ); + for(unsigned jd=0; jd<myvals.getNumberActive(); ++jd) { + unsigned ider=myvals.getActiveIndex(jd); + mymat_ders( icomp, ider ) += prefactor*myvals.getDerivative( 1, ider ); } - } - if( !serialCalculation() ) comm.Sum( mymat_ders ); + } + } + if( !serialCalculation() ) comm.Sum( mymat_ders ); - for(unsigned j=0;j<getNumberOfComponents();++j){ - Value* val=getPntrToComponent(j); - for(unsigned i=0;i<getNumberOfDerivatives();++i) val->addDerivative( i, mymat_ders(j,i) ); - } + for(unsigned j=0; j<getNumberOfComponents(); ++j) { + Value* val=getPntrToComponent(j); + for(unsigned i=0; i<getNumberOfDerivatives(); ++i) val->addDerivative( i, mymat_ders(j,i) ); + } } -void Sprint::apply(){ +void Sprint::apply() { std::vector<Vector>& f(modifyForces()); Tensor& v(modifyVirial()); unsigned nat=getNumberOfAtoms(); std::vector<double> forces( 3*getNumberOfAtoms() + 9 ); - for(unsigned i=0;i<getNumberOfComponents();++i){ - if( getPntrToComponent(i)->applyForce( forces ) ){ - for(unsigned j=0;j<nat;++j){ - f[j][0]+=forces[3*j+0]; - f[j][1]+=forces[3*j+1]; - f[j][2]+=forces[3*j+2]; - } - v(0,0)+=forces[3*nat+0]; - v(0,1)+=forces[3*nat+1]; - v(0,2)+=forces[3*nat+2]; - v(1,0)+=forces[3*nat+3]; - v(1,1)+=forces[3*nat+4]; - v(1,2)+=forces[3*nat+5]; - v(2,0)+=forces[3*nat+6]; - v(2,1)+=forces[3*nat+7]; - v(2,2)+=forces[3*nat+8]; - } + for(unsigned i=0; i<getNumberOfComponents(); ++i) { + if( getPntrToComponent(i)->applyForce( forces ) ) { + for(unsigned j=0; j<nat; ++j) { + f[j][0]+=forces[3*j+0]; + f[j][1]+=forces[3*j+1]; + f[j][2]+=forces[3*j+2]; + } + v(0,0)+=forces[3*nat+0]; + v(0,1)+=forces[3*nat+1]; + v(0,2)+=forces[3*nat+2]; + v(1,0)+=forces[3*nat+3]; + v(1,1)+=forces[3*nat+4]; + v(1,2)+=forces[3*nat+5]; + v(2,0)+=forces[3*nat+6]; + v(2,1)+=forces[3*nat+7]; + v(2,2)+=forces[3*nat+8]; + } } } diff --git a/src/adjmat/TopologyMatrix.cpp b/src/adjmat/TopologyMatrix.cpp index 4f692010d..caa8856c7 100644 --- a/src/adjmat/TopologyMatrix.cpp +++ b/src/adjmat/TopologyMatrix.cpp @@ -40,11 +40,11 @@ namespace adjmat { class TopologyMatrix : public AdjacencyMatrixBase { private: -/// The width to use for the kernel density estimation and the +/// The width to use for the kernel density estimation and the /// sizes of the bins to be used in kernel density estimation double sigma, radmax2; std::string kerneltype; -/// The maximum number of bins that will be used +/// The maximum number of bins that will be used /// This is calculated based on the dmax of the switching functions unsigned maxbins; /// The volume of the cells @@ -71,23 +71,23 @@ public: /// This does nothing double compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ) const ; /// Calculate the contribution from one of the atoms in the third element of the pack - void calculateForThreeAtoms( const unsigned& iat, const Vector& d1, const double& d1_len, - HistogramBead& bead, multicolvar::AtomValuePack& myatoms ) const ; + void calculateForThreeAtoms( const unsigned& iat, const Vector& d1, const double& d1_len, + HistogramBead& bead, multicolvar::AtomValuePack& myatoms ) const ; }; PLUMED_REGISTER_ACTION(TopologyMatrix,"TOPOLOGY_MATRIX") -void TopologyMatrix::registerKeywords( Keywords& keys ){ +void TopologyMatrix::registerKeywords( Keywords& keys ) { AdjacencyMatrixBase::registerKeywords( keys ); keys.add("atoms","NODES","The list of atoms for which you would like to calculate the contact matrix. The atoms involved must be specified " - "as a list of labels of \\ref mcolv or labels of a \\ref multicolvarfunction actions. If you would just like to use " - "the atomic positions you can use a \\ref DENSITY command to specify a group of atoms. Specifying your atomic positions using labels of " - "other \\ref mcolv or \\ref multicolvarfunction commands is useful, however, as you can then exploit a much wider " - "variety of functions of the contact matrix as described in \\ref contactmatrix"); + "as a list of labels of \\ref mcolv or labels of a \\ref multicolvarfunction actions. If you would just like to use " + "the atomic positions you can use a \\ref DENSITY command to specify a group of atoms. Specifying your atomic positions using labels of " + "other \\ref mcolv or \\ref multicolvarfunction commands is useful, however, as you can then exploit a much wider " + "variety of functions of the contact matrix as described in \\ref contactmatrix"); keys.add("atoms","ATOMS",""); keys.add("numbered","SWITCH","This keyword is used if you want to employ an alternative to the continuous swiching function defined above. " - "The following provides information on the \\ref switchingfunction that are available. " - "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); + "The following provides information on the \\ref switchingfunction that are available. " + "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); keys.add("numbered","RADIUS",""); keys.add("numbered","CYLINDER_SWITCH","a switching function on ( r_ij . r_ik - 1 )/r_ij"); keys.add("numbered","BIN_SIZE","the size to use for the bins"); @@ -98,8 +98,8 @@ void TopologyMatrix::registerKeywords( Keywords& keys ){ } TopologyMatrix::TopologyMatrix( const ActionOptions& ao ): -Action(ao), -AdjacencyMatrixBase(ao) + Action(ao), + AdjacencyMatrixBase(ao) { readMaxThreeSpeciesMatrix("NODES", "FAKE", "FAKE", "ATOMS", true ); unsigned nrows, ncols, ndonor_types; retrieveTypeDimensions( nrows, ncols, ndonor_types ); @@ -113,29 +113,29 @@ AdjacencyMatrixBase(ao) // Read in threshold for density cutoff std::string errors, thresh_sw_str; parse("DENSITY_THRESHOLD",thresh_sw_str); threshold_switch.set(thresh_sw_str, errors ); - if( errors.length()>0 ) error("errors in DENSITY_THRESHOLD switching function : " + errors ); + if( errors.length()>0 ) error("errors in DENSITY_THRESHOLD switching function : " + errors ); log.printf(" threshold on density of atoms in cylinder equals %s\n",threshold_switch.description().c_str() ); - for(unsigned i=0;i<getNumberOfNodeTypes();++i){ - for(unsigned j=0;j<getNumberOfNodeTypes();++j){ - double r=cylinder_sw(i,j).get_d0() + cylinder_sw(i,j).get_r0(); - cell_volume(i,j)=binw_mat(i,j)*pi*r*r; - } + for(unsigned i=0; i<getNumberOfNodeTypes(); ++i) { + for(unsigned j=0; j<getNumberOfNodeTypes(); ++j) { + double r=cylinder_sw(i,j).get_d0() + cylinder_sw(i,j).get_r0(); + cell_volume(i,j)=binw_mat(i,j)*pi*r*r; + } } // Find the largest sf cutoff double sfmax=switchingFunction(0,0).get_dmax(); double rfmax=cylinder_sw(0,0).get_dmax(); - for(unsigned i=0;i<getNumberOfNodeTypes();++i){ - for(unsigned j=0;j<getNumberOfNodeTypes();++j){ - double tsf=switchingFunction(i,j).get_dmax(); - if( tsf>sfmax ) sfmax=tsf; - double rsf=cylinder_sw(i,j).get_dmax(); - if( rsf>rfmax ) rfmax=rsf; - } + for(unsigned i=0; i<getNumberOfNodeTypes(); ++i) { + for(unsigned j=0; j<getNumberOfNodeTypes(); ++j) { + double tsf=switchingFunction(i,j).get_dmax(); + if( tsf>sfmax ) sfmax=tsf; + double rsf=cylinder_sw(i,j).get_dmax(); + if( rsf>rfmax ) rfmax=rsf; + } } // Get the width of the bead - HistogramBead bead; bead.isNotPeriodic(); + HistogramBead bead; bead.isNotPeriodic(); bead.setKernelType( kerneltype ); bead.set( 0.0, 1.0, sigma ); double radmax = sfmax/2.0 + bead.getCutoff(); radmax2=radmax*radmax; @@ -144,13 +144,13 @@ AdjacencyMatrixBase(ao) setLinkCellCutoff( sfmax, sqrt( radmax*radmax + rfmax*rfmax ) ); double maxsize=0; - for(unsigned i=0;i<getNumberOfNodeTypes();++i){ - for(unsigned j=0;j<getNumberOfNodeTypes();++j){ - if( binw_mat(i,j)>maxsize ) maxsize=binw_mat(i,j); - } + for(unsigned i=0; i<getNumberOfNodeTypes(); ++i) { + for(unsigned j=0; j<getNumberOfNodeTypes(); ++j) { + if( binw_mat(i,j)>maxsize ) maxsize=binw_mat(i,j); + } } // Set the maximum number of bins that we will need to compute - maxbins = std::floor( sfmax / maxsize ) + 1; + maxbins = std::floor( sfmax / maxsize ) + 1; // Need to resize functions again here to ensure that vector sizes // are set correctly in AdjacencyMatrixVessel resizeFunctions(); @@ -160,27 +160,27 @@ unsigned TopologyMatrix::getNumberOfQuantities() const { return maxbins+3; } -void TopologyMatrix::setupConnector( const unsigned& id, const unsigned& i, const unsigned& j, const std::vector<std::string>& desc ){ +void TopologyMatrix::setupConnector( const unsigned& id, const unsigned& i, const unsigned& j, const std::vector<std::string>& desc ) { plumed_assert( id<4 ); - if( id==0 ){ - std::string errors; switchingFunction(j,i).set(desc[0],errors); - if( errors.length()!=0 ) error("problem reading switching function description " + errors); - if( j!=i) switchingFunction(i,j).set(desc[0],errors); - log.printf(" %u th and %u th multicolvar groups must be within %s\n",i+1,j+1,(switchingFunction(i,j).description()).c_str() ); - } else if( id==1 ){ - std::string errors; cylinder_sw(j,i).set(desc[0],errors); - if( errors.length()!=0 ) error("problem reading switching function description " + errors); - if( j!=i) cylinder_sw(i,j).set(desc[0],errors); - log.printf(" there must be not atoms within the cylinder connections atoms of multicolvar groups %u th and %u th. This cylinder has radius %s \n",i+1,j+1,(cylinder_sw(i,j).description()).c_str() ); - } else if( id==2 ){ - std::string errors; low_sf(j,i).set(desc[0],errors); - if( errors.length()!=0 ) error("problem reading switching function description " + errors); - if( j!=i ) low_sf(i,j).set(desc[0],errors); - log.printf(" %u th and %u th multicolvar groups must be further apart than %s\n",i+1,j+1,(low_sf(j,i).description()).c_str() ); - } else if( id==3 ){ - Tools::convert( desc[0], binw_mat(j,i) ); - if( i!=j ) binw_mat(i,j)=binw_mat(j,i); - log.printf(" cylinder for %u th and %u th multicolvar groups is split into bins of length %f \n",i,j,binw_mat(i,j) ); + if( id==0 ) { + std::string errors; switchingFunction(j,i).set(desc[0],errors); + if( errors.length()!=0 ) error("problem reading switching function description " + errors); + if( j!=i) switchingFunction(i,j).set(desc[0],errors); + log.printf(" %u th and %u th multicolvar groups must be within %s\n",i+1,j+1,(switchingFunction(i,j).description()).c_str() ); + } else if( id==1 ) { + std::string errors; cylinder_sw(j,i).set(desc[0],errors); + if( errors.length()!=0 ) error("problem reading switching function description " + errors); + if( j!=i) cylinder_sw(i,j).set(desc[0],errors); + log.printf(" there must be not atoms within the cylinder connections atoms of multicolvar groups %u th and %u th. This cylinder has radius %s \n",i+1,j+1,(cylinder_sw(i,j).description()).c_str() ); + } else if( id==2 ) { + std::string errors; low_sf(j,i).set(desc[0],errors); + if( errors.length()!=0 ) error("problem reading switching function description " + errors); + if( j!=i ) low_sf(i,j).set(desc[0],errors); + log.printf(" %u th and %u th multicolvar groups must be further apart than %s\n",i+1,j+1,(low_sf(j,i).description()).c_str() ); + } else if( id==3 ) { + Tools::convert( desc[0], binw_mat(j,i) ); + if( i!=j ) binw_mat(i,j)=binw_mat(j,i); + log.printf(" cylinder for %u th and %u th multicolvar groups is split into bins of length %f \n",i,j,binw_mat(i,j) ); } } @@ -199,48 +199,48 @@ double TopologyMatrix::compute( const unsigned& tindex, multicolvar::AtomValuePa HistogramBead bead; bead.isNotPeriodic(); bead.setKernelType( kerneltype ); // Initialise to zero density on all bins - for(unsigned bin=0;bin<maxbins;++bin) myatoms.setValue(bin+1,0); + for(unsigned bin=0; bin<maxbins; ++bin) myatoms.setValue(bin+1,0); // Calculate whether or not atoms 1 and 2 are within cutoff (can use delta here as pbc are done in atom setup) Vector d1 = delta( myatoms.getPosition(0), myatoms.getPosition(1) ); double d1_len = d1.modulo(); d1 = d1 / d1_len; // Convert vector into director - for(unsigned i=2;i<myatoms.getNumberOfAtoms();++i) calculateForThreeAtoms( i, d1, d1_len, bead, myatoms ); + for(unsigned i=2; i<myatoms.getNumberOfAtoms(); ++i) calculateForThreeAtoms( i, d1, d1_len, bead, myatoms ); // std::vector<double> binvals( 1+maxbins ); for(unsigned i=1;i<maxbins;++i) binvals[i]=myatoms.getValue(i); // unsigned ii; double fdf; //std::cout<<"HELLO DENSITY "<<myatoms.getIndex(0)<<" "<<myatoms.getIndex(1)<<" "<<transformStoredValues( binvals, ii, fdf )<<std::endl; // Now find the element for which the density is maximal unsigned vout=2; double max=myatoms.getValue( 2 ); - for(unsigned i=3;i<myatoms.getUnderlyingMultiValue().getNumberOfValues()-1;++i){ - if( myatoms.getValue(i)>max ){ max=myatoms.getValue(i); vout=i; } + for(unsigned i=3; i<myatoms.getUnderlyingMultiValue().getNumberOfValues()-1; ++i) { + if( myatoms.getValue(i)>max ) { max=myatoms.getValue(i); vout=i; } } // Calculate value and derivative of switching function between atoms 1 and 2 double dfuncl, sw = switchingFunction( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) ).calculate( d1_len, dfuncl ); // Transform the density double df, tsw = threshold_switch.calculate( max, df ); - if( !doNotCalculateDerivatives() ){ - // Factor of d1_len is required here because d1 is normalized - d1 *= d1_len; - addAtomDerivatives( 2+maxbins, 0, -dfuncl*d1, myatoms ); - addAtomDerivatives( 2+maxbins, 1, dfuncl*d1, myatoms ); - myatoms.addBoxDerivatives( 2+maxbins, (-dfuncl)*Tensor(d1,d1) ); - // Update active atoms so that next bit works - updateActiveAtoms( myatoms ); - // Now finish caclulation of derivatives - MultiValue& myvals=myatoms.getUnderlyingMultiValue(); - for(unsigned jd=0;jd<myvals.getNumberActive();++jd){ - unsigned ider=myvals.getActiveIndex(jd); - myvals.addDerivative( 1, ider, sw*df*max*myvals.getDerivative( vout, ider ) + tsw*myvals.getDerivative( 2+maxbins, ider ) ); - } + if( !doNotCalculateDerivatives() ) { + // Factor of d1_len is required here because d1 is normalized + d1 *= d1_len; + addAtomDerivatives( 2+maxbins, 0, -dfuncl*d1, myatoms ); + addAtomDerivatives( 2+maxbins, 1, dfuncl*d1, myatoms ); + myatoms.addBoxDerivatives( 2+maxbins, (-dfuncl)*Tensor(d1,d1) ); + // Update active atoms so that next bit works + updateActiveAtoms( myatoms ); + // Now finish caclulation of derivatives + MultiValue& myvals=myatoms.getUnderlyingMultiValue(); + for(unsigned jd=0; jd<myvals.getNumberActive(); ++jd) { + unsigned ider=myvals.getActiveIndex(jd); + myvals.addDerivative( 1, ider, sw*df*max*myvals.getDerivative( vout, ider ) + tsw*myvals.getDerivative( 2+maxbins, ider ) ); + } } return sw*tsw; } -void TopologyMatrix::calculateForThreeAtoms( const unsigned& iat, const Vector& d1, const double& d1_len, - HistogramBead& bead, multicolvar::AtomValuePack& myatoms ) const { +void TopologyMatrix::calculateForThreeAtoms( const unsigned& iat, const Vector& d1, const double& d1_len, + HistogramBead& bead, multicolvar::AtomValuePack& myatoms ) const { // Calculate if there are atoms in the cylinder (can use delta here as pbc are done in atom setup) Vector d2 = delta( myatoms.getPosition(0), myatoms.getPosition(iat) ); - if ( d2.modulo2()>radmax2 ) return; + if ( d2.modulo2()>radmax2 ) return; // Now calculate projection of d2 on d1 double proj=dotProduct(d2,d1); // This tells us if we are outside the end of the cylinder @@ -253,66 +253,66 @@ void TopologyMatrix::calculateForThreeAtoms( const unsigned& iat, const Vector& // Return if the projection is outside the length of interest if( proj<-bead.getCutoff() || proj>(lcylinder+bead.getCutoff()) ) return; - // Calculate the excess swiching function + // Calculate the excess swiching function double edf, eval = low_sf( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) ).calculate( excess, edf ); // Calculate the projection on the perpendicular distance from the center of the tube double cm = d2.modulo2() - proj*proj; // Now calculate the density in the cylinder - if( cm<cylinder_sw( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) ).get_dmax2() ){ - double dfuncr, val = cylinder_sw( getBaseColvarNumber( myatoms.getIndex(0) ), - getBaseColvarNumber( myatoms.getIndex(1) ) ).calculateSqr( cm, dfuncr ); - double cellv = cell_volume( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) ); - - Vector dc1, dc2, dc3, dd1, dd2, dd3, de1, de2, de3; - if( !doNotCalculateDerivatives() ){ - Tensor d1_a1; - // Derivative of director connecting atom1 - atom2 wrt the position of atom 1 - d1_a1(0,0) = ( -(d1[1]*d1[1]+d1[2]*d1[2])/d1_len ); // dx/dx - d1_a1(0,1) = ( d1[0]*d1[1]/d1_len ); // dx/dy - d1_a1(0,2) = ( d1[0]*d1[2]/d1_len ); // dx/dz - d1_a1(1,0) = ( d1[1]*d1[0]/d1_len ); // dy/dx - d1_a1(1,1) = ( -(d1[0]*d1[0]+d1[2]*d1[2])/d1_len ); // dy/dy - d1_a1(1,2) = ( d1[1]*d1[2]/d1_len ); - d1_a1(2,0) = ( d1[2]*d1[0]/d1_len ); - d1_a1(2,1) = ( d1[2]*d1[1]/d1_len ); - d1_a1(2,2) = ( -(d1[1]*d1[1]+d1[0]*d1[0])/d1_len ); - - // Calculate derivatives of dot product - dd1 = matmul(d2, d1_a1) - d1; - dd2 = matmul(d2, -d1_a1); - dd3 = d1; - - // Calculate derivatives of cross product - dc1 = dfuncr*( -d2 - proj*dd1 ); - dc2 = dfuncr*( -proj*dd2 ); - dc3 = dfuncr*( d2 - proj*dd3 ); - - // Calculate derivatives of excess - de1 = edf*excess*( dd1 + d1 ); - de2 = edf*excess*( dd2 - d1 ); - de3 = edf*excess*dd3; - } - - Vector g1derivf,g2derivf,lderivf; Tensor vir; - for(unsigned bin=0;bin<maxbins;++bin){ - bead.set( bin*binw, (bin+1)*binw, sigma ); - if( proj<(bin*binw-bead.getCutoff()) || proj>binw*(bin+1)+bead.getCutoff() ) continue; - double der, contr=bead.calculateWithCutoff( proj, der ) / cellv; der /= cellv; - myatoms.addValue( 2+bin, contr*val*eval ); - - if( !doNotCalculateDerivatives() ){ - g1derivf=contr*eval*dc1 + val*eval*der*dd1 + contr*val*de1; - addAtomDerivatives( 2+bin, 0, g1derivf, myatoms ); - g2derivf=contr*eval*dc2 + val*eval*der*dd2 + contr*val*de2; - addAtomDerivatives( 2+bin, 1, g2derivf, myatoms ); - lderivf=contr*eval*dc3 + val*eval*der*dd3 + contr*val*de3; - addAtomDerivatives( 2+bin, iat, lderivf, myatoms ); - // Virial - vir = -Tensor( myatoms.getPosition(0), g1derivf ) - Tensor( myatoms.getPosition(1), g2derivf ) - Tensor( myatoms.getPosition(iat), lderivf ); - myatoms.addBoxDerivatives( 2+bin, vir ); - } + if( cm<cylinder_sw( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) ).get_dmax2() ) { + double dfuncr, val = cylinder_sw( getBaseColvarNumber( myatoms.getIndex(0) ), + getBaseColvarNumber( myatoms.getIndex(1) ) ).calculateSqr( cm, dfuncr ); + double cellv = cell_volume( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(1) ) ); + + Vector dc1, dc2, dc3, dd1, dd2, dd3, de1, de2, de3; + if( !doNotCalculateDerivatives() ) { + Tensor d1_a1; + // Derivative of director connecting atom1 - atom2 wrt the position of atom 1 + d1_a1(0,0) = ( -(d1[1]*d1[1]+d1[2]*d1[2])/d1_len ); // dx/dx + d1_a1(0,1) = ( d1[0]*d1[1]/d1_len ); // dx/dy + d1_a1(0,2) = ( d1[0]*d1[2]/d1_len ); // dx/dz + d1_a1(1,0) = ( d1[1]*d1[0]/d1_len ); // dy/dx + d1_a1(1,1) = ( -(d1[0]*d1[0]+d1[2]*d1[2])/d1_len ); // dy/dy + d1_a1(1,2) = ( d1[1]*d1[2]/d1_len ); + d1_a1(2,0) = ( d1[2]*d1[0]/d1_len ); + d1_a1(2,1) = ( d1[2]*d1[1]/d1_len ); + d1_a1(2,2) = ( -(d1[1]*d1[1]+d1[0]*d1[0])/d1_len ); + + // Calculate derivatives of dot product + dd1 = matmul(d2, d1_a1) - d1; + dd2 = matmul(d2, -d1_a1); + dd3 = d1; + + // Calculate derivatives of cross product + dc1 = dfuncr*( -d2 - proj*dd1 ); + dc2 = dfuncr*( -proj*dd2 ); + dc3 = dfuncr*( d2 - proj*dd3 ); + + // Calculate derivatives of excess + de1 = edf*excess*( dd1 + d1 ); + de2 = edf*excess*( dd2 - d1 ); + de3 = edf*excess*dd3; + } + + Vector g1derivf,g2derivf,lderivf; Tensor vir; + for(unsigned bin=0; bin<maxbins; ++bin) { + bead.set( bin*binw, (bin+1)*binw, sigma ); + if( proj<(bin*binw-bead.getCutoff()) || proj>binw*(bin+1)+bead.getCutoff() ) continue; + double der, contr=bead.calculateWithCutoff( proj, der ) / cellv; der /= cellv; + myatoms.addValue( 2+bin, contr*val*eval ); + + if( !doNotCalculateDerivatives() ) { + g1derivf=contr*eval*dc1 + val*eval*der*dd1 + contr*val*de1; + addAtomDerivatives( 2+bin, 0, g1derivf, myatoms ); + g2derivf=contr*eval*dc2 + val*eval*der*dd2 + contr*val*de2; + addAtomDerivatives( 2+bin, 1, g2derivf, myatoms ); + lderivf=contr*eval*dc3 + val*eval*der*dd3 + contr*val*de3; + addAtomDerivatives( 2+bin, iat, lderivf, myatoms ); + // Virial + vir = -Tensor( myatoms.getPosition(0), g1derivf ) - Tensor( myatoms.getPosition(1), g2derivf ) - Tensor( myatoms.getPosition(iat), lderivf ); + myatoms.addBoxDerivatives( 2+bin, vir ); } + } } } diff --git a/src/analysis/Analysis.cpp b/src/analysis/Analysis.cpp index 4d76df935..989981ab6 100644 --- a/src/analysis/Analysis.cpp +++ b/src/analysis/Analysis.cpp @@ -34,7 +34,7 @@ namespace PLMD { namespace analysis { -void Analysis::registerKeywords( Keywords& keys ){ +void Analysis::registerKeywords( Keywords& keys ) { vesselbase::ActionWithAveraging::registerKeywords( keys ); keys.use("ARG"); keys.reset_style("ARG","optional"); keys.add("atoms","ATOMS","the atoms whose positions we are tracking for the purpose of analysing the data"); @@ -44,36 +44,36 @@ void Analysis::registerKeywords( Keywords& keys ){ keys.addFlag("WRITE_CHECKPOINT",false,"write out a checkpoint so that the analysis can be restarted in a later run"); keys.add("hidden","REUSE_DATA_FROM","eventually this will allow you to analyse the same set of data multiple times"); keys.add("hidden","IGNORE_REWEIGHTING","this allows you to ignore any reweighting factors"); - keys.use("RESTART"); keys.use("UPDATE_FROM"); keys.use("UPDATE_UNTIL"); keys.remove("TOL"); + keys.use("RESTART"); keys.use("UPDATE_FROM"); keys.use("UPDATE_UNTIL"); keys.remove("TOL"); } Analysis::Analysis(const ActionOptions&ao): -Action(ao), -ActionWithAveraging(ao), -nomemory(true), -write_chq(false), -reusing_data(false), -ignore_reweight(false), -idata(0), + Action(ao), + ActionWithAveraging(ao), + nomemory(true), + write_chq(false), + reusing_data(false), + ignore_reweight(false), + idata(0), //firstAnalysisDone(false), //old_norm(0.0), -ofmt("%f"), -current_args(getNumberOfArguments()), -argument_names(getNumberOfArguments()) + ofmt("%f"), + current_args(getNumberOfArguments()), + argument_names(getNumberOfArguments()) { parse("FMT",ofmt); // Read the format for output files // Make a vector containing all the argument names - for(unsigned i=0;i<getNumberOfArguments();++i) argument_names[i]=getPntrToArgument(i)->getName(); + for(unsigned i=0; i<getNumberOfArguments(); ++i) argument_names[i]=getPntrToArgument(i)->getName(); // Read in the metric style parse("METRIC",metricname); std::vector<AtomNumber> atom_numbers; ReferenceConfiguration* checkref=metricRegister().create<ReferenceConfiguration>( metricname ); // Check if we should read atoms ReferenceAtoms* hasatoms=dynamic_cast<ReferenceAtoms*>( checkref ); - if( hasatoms ){ - parseAtomList("ATOMS",atom_numbers); requestAtoms(atom_numbers); - log.printf(" monitoring positions of atoms "); - for(unsigned i=0;i<atom_numbers.size();++i) log.printf("%d ",atom_numbers[i].serial() ); - log.printf("\n"); + if( hasatoms ) { + parseAtomList("ATOMS",atom_numbers); requestAtoms(atom_numbers); + log.printf(" monitoring positions of atoms "); + for(unsigned i=0; i<atom_numbers.size(); ++i) log.printf("%d ",atom_numbers[i].serial() ); + log.printf("\n"); } // Check if we should read arguments ReferenceArguments* hasargs=dynamic_cast<ReferenceArguments*>( checkref ); @@ -83,174 +83,174 @@ argument_names(getNumberOfArguments()) delete checkref; std::string prev_analysis; parse("REUSE_DATA_FROM",prev_analysis); - if( prev_analysis.length()>0 ){ - reusing_data=true; - mydatastash=plumed.getActionSet().selectWithLabel<Analysis*>( prev_analysis ); - if( !mydatastash ) error("could not find analysis action named " + prev_analysis ); - parseFlag("IGNORE_REWEIGHTING",ignore_reweight); - if( ignore_reweight ) log.printf(" reusing data stored by %s but ignoring all reweighting\n",prev_analysis.c_str() ); - else log.printf(" reusing data stored by %s\n",prev_analysis.c_str() ); - } else { - parse("RUN",freq); - if( freq==0 ){ - log.printf(" analyzing all data in trajectory\n"); - } else { - if( freq%getStride()!=0 ) error("frequncy of running is not a multiple of the stride"); - log.printf(" running analysis every %u steps\n",freq); - ndata=freq/getStride(); data.resize( ndata ); logweights.resize( ndata ); - for(unsigned i=0;i<ndata;++i){ - data[i]=metricRegister().create<ReferenceConfiguration>( metricname ); - data[i]->setNamesAndAtomNumbers( getAbsoluteIndexes(), argument_names ); - } - } - parseFlag("WRITE_CHECKPOINT",write_chq); - if( write_chq ){ - write_chq=false; - warning("ignoring WRITE_CHECKPOINT flag because we are analyzing all data"); - } - - // We need no restart file if we are just collecting data and analyzing all of it - std::string filename = getName() + "_" + getLabel() + ".chkpnt"; - if( write_chq ) rfile.link(*this); - if( getRestart() ){ - if( !write_chq ) warning("restarting without writing a checkpoint file is somewhat strange"); - // Read in data from input file - readDataFromFile( filename ); - // Setup the restart file (append mode) - if( write_chq ) rfile.open( filename.c_str() ); // In append mode automatically because of restart - // Run the analysis if we stoped in the middle of it last time - log.printf(" restarting analysis with %u points read from restart file\n",idata); - } else if( write_chq ){ - // Setup the restart file (delete any old one) - rfile.open( filename.c_str() ); // In overwrite mode automatically because there is no restart - } - if( write_chq ){ - //rfile.addConstantField("old_normalization"); - for(unsigned i=0;i<getNumberOfArguments();++i) rfile.setupPrintValue( getPntrToArgument(i) ); + if( prev_analysis.length()>0 ) { + reusing_data=true; + mydatastash=plumed.getActionSet().selectWithLabel<Analysis*>( prev_analysis ); + if( !mydatastash ) error("could not find analysis action named " + prev_analysis ); + parseFlag("IGNORE_REWEIGHTING",ignore_reweight); + if( ignore_reweight ) log.printf(" reusing data stored by %s but ignoring all reweighting\n",prev_analysis.c_str() ); + else log.printf(" reusing data stored by %s\n",prev_analysis.c_str() ); + } else { + parse("RUN",freq); + if( freq==0 ) { + log.printf(" analyzing all data in trajectory\n"); + } else { + if( freq%getStride()!=0 ) error("frequncy of running is not a multiple of the stride"); + log.printf(" running analysis every %u steps\n",freq); + ndata=freq/getStride(); data.resize( ndata ); logweights.resize( ndata ); + for(unsigned i=0; i<ndata; ++i) { + data[i]=metricRegister().create<ReferenceConfiguration>( metricname ); + data[i]->setNamesAndAtomNumbers( getAbsoluteIndexes(), argument_names ); } + } + parseFlag("WRITE_CHECKPOINT",write_chq); + if( write_chq ) { + write_chq=false; + warning("ignoring WRITE_CHECKPOINT flag because we are analyzing all data"); + } + + // We need no restart file if we are just collecting data and analyzing all of it + std::string filename = getName() + "_" + getLabel() + ".chkpnt"; + if( write_chq ) rfile.link(*this); + if( getRestart() ) { + if( !write_chq ) warning("restarting without writing a checkpoint file is somewhat strange"); + // Read in data from input file + readDataFromFile( filename ); + // Setup the restart file (append mode) + if( write_chq ) rfile.open( filename.c_str() ); // In append mode automatically because of restart + // Run the analysis if we stoped in the middle of it last time + log.printf(" restarting analysis with %u points read from restart file\n",idata); + } else if( write_chq ) { + // Setup the restart file (delete any old one) + rfile.open( filename.c_str() ); // In overwrite mode automatically because there is no restart + } + if( write_chq ) { + //rfile.addConstantField("old_normalization"); + for(unsigned i=0; i<getNumberOfArguments(); ++i) rfile.setupPrintValue( getPntrToArgument(i) ); + } } } -void Analysis::readDataFromFile( const std::string& filename ){ +void Analysis::readDataFromFile( const std::string& filename ) { FILE* fp=fopen(filename.c_str(),"r"); - if(fp!=NULL){ - double tstep, oldtstep; - bool do_read=true, first=true; - while (do_read) { - PDB mypdb; - do_read=mypdb.readFromFilepointer(fp,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength()); - if(do_read){ - data[idata]->set( mypdb ); - data[idata]->parse("TIME",tstep); - if( !first && ((tstep-oldtstep) - getStride()*plumed.getAtoms().getTimeStep())>plumed.getAtoms().getTimeStep() ){ - error("frequency of data storage in " + filename + " is not equal to frequency of data storage plumed.dat file"); - } - data[idata]->parse("LOG_WEIGHT",logweights[idata]); - //data[idata]->parse("OLD_NORM",old_norm); - data[idata]->checkRead(); - idata++; first=false; oldtstep=tstep; - } else{ - break; - } - } + if(fp!=NULL) { + double tstep, oldtstep; + bool do_read=true, first=true; + while (do_read) { + PDB mypdb; + do_read=mypdb.readFromFilepointer(fp,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength()); + if(do_read) { + data[idata]->set( mypdb ); + data[idata]->parse("TIME",tstep); + if( !first && ((tstep-oldtstep) - getStride()*plumed.getAtoms().getTimeStep())>plumed.getAtoms().getTimeStep() ) { + error("frequency of data storage in " + filename + " is not equal to frequency of data storage plumed.dat file"); + } + data[idata]->parse("LOG_WEIGHT",logweights[idata]); + //data[idata]->parse("OLD_NORM",old_norm); + data[idata]->checkRead(); + idata++; first=false; oldtstep=tstep; + } else { + break; + } + } fclose(fp); } // if(old_norm>0) firstAnalysisDone=true; } -void Analysis::parseOutputFile( const std::string& key, std::string& filename ){ +void Analysis::parseOutputFile( const std::string& key, std::string& filename ) { parse(key,filename); if(filename=="dont output") return; - if( !getRestart() ){ - OFile ofile; ofile.link(*this); - ofile.setBackupString("analysis"); - ofile.backupAllFiles(filename); - } + if( !getRestart() ) { + OFile ofile; ofile.link(*this); + ofile.setBackupString("analysis"); + ofile.backupAllFiles(filename); + } } -void Analysis::accumulate(){ +void Analysis::accumulate() { // Don't store the first step (also don't store if we are getting data from elsewhere) if( getStep()==0 || reusing_data ) return; // This is used when we have a full quota of data from the first run - if( freq>0 && idata==logweights.size() ) return; + if( freq>0 && idata==logweights.size() ) return; // Get the arguments ready to transfer to reference configuration - for(unsigned i=0;i<getNumberOfArguments();++i) current_args[i]=getArgument(i); + for(unsigned i=0; i<getNumberOfArguments(); ++i) current_args[i]=getArgument(i); - if( freq>0){ - // Get the arguments and store them in a vector of vectors - data[idata]->setReferenceConfig( getPositions(), current_args, getMetric() ); - logweights[idata] = lweight; + if( freq>0) { + // Get the arguments and store them in a vector of vectors + data[idata]->setReferenceConfig( getPositions(), current_args, getMetric() ); + logweights[idata] = lweight; } else { - data.push_back( metricRegister().create<ReferenceConfiguration>( metricname ) ); - plumed_dbg_assert( data.size()==idata+1 ); - data[idata]->setNamesAndAtomNumbers( getAbsoluteIndexes(), argument_names ); - data[idata]->setReferenceConfig( getPositions(), current_args, getMetric() ); - logweights.push_back(lweight); - } + data.push_back( metricRegister().create<ReferenceConfiguration>( metricname ) ); + plumed_dbg_assert( data.size()==idata+1 ); + data[idata]->setNamesAndAtomNumbers( getAbsoluteIndexes(), argument_names ); + data[idata]->setReferenceConfig( getPositions(), current_args, getMetric() ); + logweights.push_back(lweight); + } // Write data to checkpoint file - if( write_chq ){ - rfile.rewind(); - data[idata]->print( rfile, getTime(), logweights[idata], atoms.getUnits().getLength()/0.1, 1.0 ); //old_norm ); - rfile.flush(); + if( write_chq ) { + rfile.rewind(); + data[idata]->print( rfile, getTime(), logweights[idata], atoms.getUnits().getLength()/0.1, 1.0 ); //old_norm ); + rfile.flush(); } // Increment data counter idata++; } -Analysis::~Analysis(){ - for(unsigned i=0;i<data.size();++i ) delete data[i]; +Analysis::~Analysis() { + for(unsigned i=0; i<data.size(); ++i ) delete data[i]; if( write_chq ) rfile.close(); } std::vector<double> Analysis::getMetric() const { // Add more exotic metrics in here -- FlexibleHill for instance std::vector<double> empty; - if( metricname=="EUCLIDEAN" ){ - empty.resize( getNumberOfArguments(), 1.0 ); + if( metricname=="EUCLIDEAN" ) { + empty.resize( getNumberOfArguments(), 1.0 ); } return empty; } double Analysis::getWeight( const unsigned& idata ) const { - if( !reusing_data ){ - plumed_dbg_assert( idata<data.size() ); - return data[idata]->getWeight(); + if( !reusing_data ) { + plumed_dbg_assert( idata<data.size() ); + return data[idata]->getWeight(); } else { - return mydatastash->getWeight(idata); + return mydatastash->getWeight(idata); } } -void Analysis::finalizeWeights( const bool& ignore_weights ){ +void Analysis::finalizeWeights( const bool& ignore_weights ) { // Check that we have the correct ammount of data if( !reusing_data && idata!=logweights.size() ) error("something has gone wrong. Am trying to run analysis but I don't have sufficient data"); double norm=0; // Reset normalization constant - if( ignore_weights ){ - for(unsigned i=0;i<logweights.size();++i){ - data[i]->setWeight(1.0); norm+=1.0; - } - } else if( nomemory ){ - // Find the maximum weight - double maxweight=logweights[0]; - for(unsigned i=1;i<getNumberOfDataPoints();++i){ - if(logweights[i]>maxweight) maxweight=logweights[i]; - } - // Calculate normalization constant - for(unsigned i=0;i<logweights.size();++i){ - norm+=exp( logweights[i]-maxweight ); - } - // Calculate weights (no memory) - for(unsigned i=0;i<logweights.size();++i){ - data[i]->setWeight( exp( logweights[i]-maxweight ) ); - } - // Calculate normalized weights (with memory) + if( ignore_weights ) { + for(unsigned i=0; i<logweights.size(); ++i) { + data[i]->setWeight(1.0); norm+=1.0; + } + } else if( nomemory ) { + // Find the maximum weight + double maxweight=logweights[0]; + for(unsigned i=1; i<getNumberOfDataPoints(); ++i) { + if(logweights[i]>maxweight) maxweight=logweights[i]; + } + // Calculate normalization constant + for(unsigned i=0; i<logweights.size(); ++i) { + norm+=exp( logweights[i]-maxweight ); + } + // Calculate weights (no memory) + for(unsigned i=0; i<logweights.size(); ++i) { + data[i]->setWeight( exp( logweights[i]-maxweight ) ); + } + // Calculate normalized weights (with memory) } else { - plumed_merror("analysis can now only support block averages"); - // if( !firstAnalysisDone ) - // finalizeWeightsNoLogSums( 1.0 ); - // else finalizeWeightsNoLogSums( old_norm ); + plumed_merror("analysis can now only support block averages"); + // if( !firstAnalysisDone ) + // finalizeWeightsNoLogSums( 1.0 ); + // else finalizeWeightsNoLogSums( old_norm ); } } @@ -264,26 +264,26 @@ void Analysis::finalizeWeights( const bool& ignore_weights ){ void Analysis::getDataPoint( const unsigned& idata, std::vector<double>& point, double& weight ) const { plumed_dbg_assert( getNumberOfAtoms()==0 ); - if( !reusing_data ){ - plumed_dbg_assert( idata<logweights.size() && point.size()==getNumberOfArguments() ); - for(unsigned i=0;i<point.size();++i) point[i]=data[idata]->getReferenceArgument(i); - weight=data[idata]->getWeight(); + if( !reusing_data ) { + plumed_dbg_assert( idata<logweights.size() && point.size()==getNumberOfArguments() ); + for(unsigned i=0; i<point.size(); ++i) point[i]=data[idata]->getReferenceArgument(i); + weight=data[idata]->getWeight(); } else { - return mydatastash->getDataPoint( idata, point, weight ); + return mydatastash->getDataPoint( idata, point, weight ); } } -void Analysis::runAnalysis(){ +void Analysis::runAnalysis() { // Note : could add multiple walkers here - simply read in the data from all // other walkers here if we are writing the check points. - // Calculate the final weights from the log weights - if( !reusing_data ){ - finalizeWeights( ignore_reweight ); + // Calculate the final weights from the log weights + if( !reusing_data ) { + finalizeWeights( ignore_reweight ); } else { - mydatastash->finalizeWeights( ignore_reweight ); - // norm=mydatastash->retrieveNorm(); + mydatastash->finalizeWeights( ignore_reweight ); + // norm=mydatastash->retrieveNorm(); } // This ensures everything is set up to run the calculation // if( single_run ) setAnalysisStride( single_run, freq ); @@ -294,15 +294,15 @@ void Analysis::runAnalysis(){ } -void Analysis::performOperations( const bool& from_update ){ +void Analysis::performOperations( const bool& from_update ) { accumulate(); - if( freq>0 ){ - if( getStep()>0 && getStep()%freq==0 ) runAnalysis(); - else if( idata==logweights.size() ) error("something has gone wrong. Probably a wrong initial time on restart"); + if( freq>0 ) { + if( getStep()>0 && getStep()%freq==0 ) runAnalysis(); + else if( idata==logweights.size() ) error("something has gone wrong. Probably a wrong initial time on restart"); } } -bool Analysis::getPeriodicityInformation(const unsigned& i, std::string& dmin, std::string& dmax){ +bool Analysis::getPeriodicityInformation(const unsigned& i, std::string& dmin, std::string& dmax) { bool isperiodic=getPntrToArgument(i)->isPeriodic(); if(isperiodic) getPntrToArgument(i)->getDomain(dmin,dmax); return isperiodic; @@ -311,7 +311,7 @@ bool Analysis::getPeriodicityInformation(const unsigned& i, std::string& dmin, s void Analysis::runFinalJobs() { if( freq>0 ) return; if( getNumberOfDataPoints()==0 ) error("no data is available for analysis"); - runAnalysis(); + runAnalysis(); } } diff --git a/src/analysis/Analysis.h b/src/analysis/Analysis.h index 2a6c371af..44b608277 100644 --- a/src/analysis/Analysis.h +++ b/src/analysis/Analysis.h @@ -34,7 +34,7 @@ namespace analysis { /** \ingroup INHERIT -This is the abstract base class to use for implementing new methods for analyzing the trajectory, within it there +This is the abstract base class to use for implementing new methods for analyzing the trajectory, within it there is information as to how to go about implementing a new analysis method. */ @@ -82,7 +82,7 @@ private: /// Get the metric if we are using malonobius distance and flexible hill std::vector<double> getMetric() const ; protected: -/// List of argument names +/// List of argument names std::vector<std::string> argument_names; /// This is used to read in output file names for analysis methods. When /// this method is used and the calculation is not restarted old analysis @@ -98,10 +98,10 @@ protected: double getWeight( const unsigned& idata ) const ; /// Retrieve the ith point void getDataPoint( const unsigned& idata, std::vector<double>& point, double& weight ) const ; -/// Returns true if argument i is periodic together with the domain +/// Returns true if argument i is periodic together with the domain bool getPeriodicityInformation(const unsigned& i, std::string& dmin, std::string& dmax); /// Are we analyzing each data block separately (if we are not this also returns the old normalization ) - bool usingMemory() const; + bool usingMemory() const; /// Return the format to use for numbers in output files std::string getOutputFormat() const ; /// Finalize the weights without using the log sums @@ -110,14 +110,14 @@ public: static void registerKeywords( Keywords& keys ); explicit Analysis(const ActionOptions&); ~Analysis(); - void calculate(){} - void apply(){} + void calculate() {} + void apply() {} void accumulate(); void performOperations( const bool& from_update ); virtual void performAnalysis()=0; void runFinalJobs(); void runAnalysis(); - bool isPeriodic(){ plumed_error(); return false; } + bool isPeriodic() { plumed_error(); return false; } /// Convert the stored log weights to proper weights virtual void finalizeWeights( const bool& ignore_weights ); }; @@ -129,20 +129,20 @@ std::string Analysis::getMetricName() const { inline unsigned Analysis::getNumberOfDataPoints() const { - if( !reusing_data ){ - plumed_dbg_assert( data.size()==logweights.size() ); - return data.size(); + if( !reusing_data ) { + plumed_dbg_assert( data.size()==logweights.size() ); + return data.size(); } else { - return mydatastash->getNumberOfDataPoints(); + return mydatastash->getNumberOfDataPoints(); } } inline bool Analysis::usingMemory() const { - if( !reusing_data ){ - return !nomemory; + if( !reusing_data ) { + return !nomemory; } else { - return mydatastash->usingMemory(); + return mydatastash->usingMemory(); } } diff --git a/src/analysis/AnalysisWithLandmarks.cpp b/src/analysis/AnalysisWithLandmarks.cpp index 4ff419e92..9cd67c52f 100644 --- a/src/analysis/AnalysisWithLandmarks.cpp +++ b/src/analysis/AnalysisWithLandmarks.cpp @@ -25,7 +25,7 @@ //+PLUMEDOC INTERNAL landmarkselection /* -This is currently a filler page. +This is currently a filler page. Just use LANDMARKS=ALL. More complex versions will appear in later versions. @@ -35,37 +35,37 @@ Just use LANDMARKS=ALL. More complex versions will appear in later versions. namespace PLMD { namespace analysis { -void AnalysisWithLandmarks::registerKeywords( Keywords& keys ){ +void AnalysisWithLandmarks::registerKeywords( Keywords& keys ) { Analysis::registerKeywords( keys ); keys.add("compulsory","LANDMARKS","ALL","only use a subset of the data that was collected. " - "For more information on the landmark selection algorithms that are available in " - "plumed see \\ref landmarkselection."); + "For more information on the landmark selection algorithms that are available in " + "plumed see \\ref landmarkselection."); } AnalysisWithLandmarks::AnalysisWithLandmarks( const ActionOptions& ao): -Action(ao), -Analysis(ao), -data_to_analyze(NULL) + Action(ao), + Analysis(ao), + data_to_analyze(NULL) { - std::string linput; parse("LANDMARKS",linput); - std::vector<std::string> words=Tools::getWords(linput); - landmarkSelector=landmarkRegister().create( LandmarkSelectionOptions(words,this) ); - log.printf(" %s\n", landmarkSelector->description().c_str() ); + std::string linput; parse("LANDMARKS",linput); + std::vector<std::string> words=Tools::getWords(linput); + landmarkSelector=landmarkRegister().create( LandmarkSelectionOptions(words,this) ); + log.printf(" %s\n", landmarkSelector->description().c_str() ); } -AnalysisWithLandmarks::~AnalysisWithLandmarks(){ - delete landmarkSelector; +AnalysisWithLandmarks::~AnalysisWithLandmarks() { + delete landmarkSelector; } -void AnalysisWithLandmarks::setDataToAnalyze( MultiReferenceBase* mydata ){ - data_to_analyze=mydata; +void AnalysisWithLandmarks::setDataToAnalyze( MultiReferenceBase* mydata ) { + data_to_analyze=mydata; } unsigned AnalysisWithLandmarks::getNumberOfLandmarks() const { return landmarkSelector->getNumberOfLandmarks(); } -void AnalysisWithLandmarks::performAnalysis(){ +void AnalysisWithLandmarks::performAnalysis() { plumed_assert( data_to_analyze ); landmarkSelector->selectLandmarks( data_to_analyze ); analyzeLandmarks(); diff --git a/src/analysis/AnalysisWithLandmarks.h b/src/analysis/AnalysisWithLandmarks.h index 3eb2c6a02..b129a4d01 100644 --- a/src/analysis/AnalysisWithLandmarks.h +++ b/src/analysis/AnalysisWithLandmarks.h @@ -33,12 +33,12 @@ namespace analysis { class LandmarkSelectionBase; class AnalysisWithLandmarks : public Analysis { -friend class LandmarkSelectionBase; -friend class CopyAllFrames; + friend class LandmarkSelectionBase; + friend class CopyAllFrames; private: /// This object selects landmarks from the data LandmarkSelectionBase* landmarkSelector; -/// A pointer to the data we are analyzing +/// A pointer to the data we are analyzing MultiReferenceBase* data_to_analyze; protected: /// Set the data that needs to be analyzed @@ -53,7 +53,7 @@ public: void performAnalysis(); virtual void analyzeLandmarks()=0; /// This does nothing - void performTask( const unsigned& , const unsigned& , MultiValue& ) const ; + void performTask( const unsigned&, const unsigned&, MultiValue& ) const ; }; } diff --git a/src/analysis/Average.cpp b/src/analysis/Average.cpp index ec2da2ad2..c96b2556b 100644 --- a/src/analysis/Average.cpp +++ b/src/analysis/Average.cpp @@ -23,8 +23,8 @@ #include "core/ActionRegister.h" #include "AverageVessel.h" -//+PLUMEDOC GRIDCALC AVERAGE -/* +//+PLUMEDOC GRIDCALC AVERAGE +/* Calculate the ensemble average of a collective variable The ensemble average for a non-periodic, collective variable, \f$s\f$ is given by the following expression: @@ -34,8 +34,8 @@ The ensemble average for a non-periodic, collective variable, \f$s\f$ is given b \f] Here the sum runs over a the trajectory and \f$s(t')\f$ is used to denote the value of the collective variable -at time \f$t'\f$. The final quantity evalulated is a weighted -average as the weights, \f$w(t')\f$, allow us to negate the effect any bias might have on the region of phase space +at time \f$t'\f$. The final quantity evalulated is a weighted +average as the weights, \f$w(t')\f$, allow us to negate the effect any bias might have on the region of phase space sampled by the system. This is discussed in the section of the manual on \ref Analysis. When the variable is periodic (e.g. \ref TORSION) and has a value, \f$s\f$, in \f$a \le s \le b\f$ the ensemble average is evaluated using: @@ -47,12 +47,12 @@ When the variable is periodic (e.g. \ref TORSION) and has a value, \f$s\f$, in \ \par Examples The following example calculates the ensemble average for the distance between atoms 1 and 2 -and output this to a file called COLVAR. In this example it is assumed that no bias is acting -on the system and that the weights, \f$w(t')\f$ in the formulae above can thus all be set equal -to one. +and output this to a file called COLVAR. In this example it is assumed that no bias is acting +on the system and that the weights, \f$w(t')\f$ in the formulae above can thus all be set equal +to one. \verbatim -d1: DISTANCE ATOMS=1,2 +d1: DISTANCE ATOMS=1,2 d1a: AVERAGE ARG=d1 PRINT ARG=d1a FILE=colvar STRIDE=100 \endverbatim @@ -60,23 +60,23 @@ PRINT ARG=d1a FILE=colvar STRIDE=100 The following example calculates the ensemble average for the torsional angle involving atoms 1, 2, 3 and 4. At variance with the previous example this quantity is periodic so the second formula in the above introduction is used to calculate the average. Furthermore, by using the CLEAR keyword we have specified that block averages -are to be calculated. Consequently, after 100 steps all the information aquired thus far in the simulation is -forgotten and the process of averaging is begun again. The quantities output in the colvar file are thus the +are to be calculated. Consequently, after 100 steps all the information aquired thus far in the simulation is +forgotten and the process of averaging is begun again. The quantities output in the colvar file are thus the block averages taken over the first 100 frames of the trajectory, the block average over the second 100 frames of trajectory and so on. \verbatim -t1: TORSION ATOMS=1,2,3,4 +t1: TORSION ATOMS=1,2,3,4 t1a: AVERAGE ARG=t1 CLEAR=100 PRINT ARG=t1a FILE=colvar STRIDE=100 \endverbatim This third example incorporates a bias. Notice that the effect the bias has on the ensemble average is removed by taking advantage of the \ref REWEIGHT_BIAS method. The final ensemble averages output to the file are thus block ensemble averages for the -unbiased canononical ensemble at a temperature of 300 K. +unbiased canononical ensemble at a temperature of 300 K. \verbatim -t1: TORSION ATOMS=1,2,3,4 +t1: TORSION ATOMS=1,2,3,4 RESTRAINT ARG=t1 AT=pi KAPPA=100. ww: REWEIGHT_BIAS TEMP=300 t1a: AVERAGE ARG=t1 LOGWEIGHTS=ww CLEAR=100 @@ -95,47 +95,47 @@ private: public: static void registerKeywords( Keywords& keys ); explicit Average( const ActionOptions& ); - void calculate(){} - void apply(){} + void calculate() {} + void apply() {} void performOperations( const bool& from_update ); void finishAveraging(); - bool isPeriodic(){ return false; } - void performTask( const unsigned& , const unsigned& , MultiValue& ) const { plumed_error(); } + bool isPeriodic() { return false; } + void performTask( const unsigned&, const unsigned&, MultiValue& ) const { plumed_error(); } }; PLUMED_REGISTER_ACTION(Average,"AVERAGE") -void Average::registerKeywords( Keywords& keys ){ +void Average::registerKeywords( Keywords& keys ) { vesselbase::ActionWithAveraging::registerKeywords( keys ); keys.use("ARG"); - keys.remove("SERIAL"); keys.remove("LOWMEM"); + keys.remove("SERIAL"); keys.remove("LOWMEM"); } Average::Average( const ActionOptions& ao ): -Action(ao), -ActionWithAveraging(ao) + Action(ao), + ActionWithAveraging(ao) { - addValue(); // Create a value so that we can output the average - if( getNumberOfArguments()!=1 ) error("only one quantity can be averaged at a time"); - std::string instring; - if( getPntrToArgument(0)->isPeriodic() ){ - std::string min, max; getPntrToArgument(0)->getDomain(min,max); - instring = "PERIODIC=" + min + "," + max; setPeriodic( min, max ); - } else { - setNotPeriodic(); - } - // Create a vessel to hold the average - vesselbase::VesselOptions da("myaverage","",-1,instring,this); - Keywords keys; AverageVessel::registerKeywords( keys ); - vesselbase::VesselOptions dar( da, keys ); - myaverage = new AverageVessel(dar); setAveragingAction( myaverage, false ); + addValue(); // Create a value so that we can output the average + if( getNumberOfArguments()!=1 ) error("only one quantity can be averaged at a time"); + std::string instring; + if( getPntrToArgument(0)->isPeriodic() ) { + std::string min, max; getPntrToArgument(0)->getDomain(min,max); + instring = "PERIODIC=" + min + "," + max; setPeriodic( min, max ); + } else { + setNotPeriodic(); + } + // Create a vessel to hold the average + vesselbase::VesselOptions da("myaverage","",-1,instring,this); + Keywords keys; AverageVessel::registerKeywords( keys ); + vesselbase::VesselOptions dar( da, keys ); + myaverage = new AverageVessel(dar); setAveragingAction( myaverage, false ); } -void Average::performOperations( const bool& from_update ){ - myaverage->accumulate( cweight, getArgument(0) ); +void Average::performOperations( const bool& from_update ) { + myaverage->accumulate( cweight, getArgument(0) ); } -void Average::finishAveraging(){ - setValue( myaverage->getAverage() ); +void Average::finishAveraging() { + setValue( myaverage->getAverage() ); } } diff --git a/src/analysis/AverageVessel.cpp b/src/analysis/AverageVessel.cpp index 136169653..96e4a72fe 100644 --- a/src/analysis/AverageVessel.cpp +++ b/src/analysis/AverageVessel.cpp @@ -24,30 +24,30 @@ namespace PLMD { namespace analysis { -void AverageVessel::registerKeywords( Keywords& keys ){ +void AverageVessel::registerKeywords( Keywords& keys ) { vesselbase::AveragingVessel::registerKeywords( keys ); keys.add("optional","PERIODIC","is the quantity being averaged periodic and what is its domain"); } AverageVessel::AverageVessel( const vesselbase::VesselOptions& da): -AveragingVessel(da) + AveragingVessel(da) { parseVector("PERIODIC",domain); plumed_assert( domain.size()==2 || domain.size()==0 ); } -void AverageVessel::resize(){ - resizeBuffer(0); +void AverageVessel::resize() { + resizeBuffer(0); if( domain.size()==2 ) setDataSize(2); else setDataSize(1); } -void AverageVessel::accumulate( const double& weight, const double& val ){ - if( domain.size()==2 ){ - // Average with Berry Phase - double tval = 2*pi*( val - domain[0] ) / ( domain[1] - domain[0] ); - addDataElement( 0, weight*sin(tval) ); addDataElement( 1, weight*cos(tval) ); - } else addDataElement( 0, weight*val ); +void AverageVessel::accumulate( const double& weight, const double& val ) { + if( domain.size()==2 ) { + // Average with Berry Phase + double tval = 2*pi*( val - domain[0] ) / ( domain[1] - domain[0] ); + addDataElement( 0, weight*sin(tval) ); addDataElement( 1, weight*cos(tval) ); + } else addDataElement( 0, weight*val ); } double AverageVessel::getAverage() const { diff --git a/src/analysis/AverageVessel.h b/src/analysis/AverageVessel.h index 6b1f23971..3b056b8c4 100644 --- a/src/analysis/AverageVessel.h +++ b/src/analysis/AverageVessel.h @@ -29,21 +29,21 @@ namespace analysis { class AverageVessel : public vesselbase::AveragingVessel { private: - std::vector<double> domain; + std::vector<double> domain; public: /// keywords - static void registerKeywords( Keywords& keys ); + static void registerKeywords( Keywords& keys ); /// Constructor - explicit AverageVessel( const vesselbase::VesselOptions& ); + explicit AverageVessel( const vesselbase::VesselOptions& ); /// Set the size of the data vessel - void resize(); + void resize(); /// This does nothing - void calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const ; - std::string description(){ return ""; } + void calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const ; + std::string description() { return ""; } /// Accumulate the average - void accumulate( const double& weight, const double& val ); + void accumulate( const double& weight, const double& val ); /// Get the average value - double getAverage() const ; + double getAverage() const ; }; } diff --git a/src/analysis/ClassicalMultiDimensionalScaling.cpp b/src/analysis/ClassicalMultiDimensionalScaling.cpp index 6326dab17..93bb25f1d 100644 --- a/src/analysis/ClassicalMultiDimensionalScaling.cpp +++ b/src/analysis/ClassicalMultiDimensionalScaling.cpp @@ -29,26 +29,26 @@ namespace analysis { //+PLUMEDOC DIMRED CLASSICAL_MDS /* -Create a low-dimensional projection of a trajectory using the classical multidimensional +Create a low-dimensional projection of a trajectory using the classical multidimensional scaling algorithm. -Multidimensional scaling (MDS) is similar to what is done when you make a map. You start with distances -between London, Belfast, Paris and Dublin and then you try to arrange points on a piece of paper so that the (suitably scaled) -distances between the points in your map representing each of those cities are related to the true distances between the cities. -Stating this more mathematically MDS endeavors to find an <a href="http://en.wikipedia.org/wiki/Isometry">isometry</a> -between points distributed in a high-dimensional space and a set of points distributed in a low-dimensional plane. -In other words, if we have \f$M\f$ \f$D\f$-dimensional points, \f$\mathbf{X}\f$, -and we can calculate dissimilarities between pairs them, \f$D_{ij}\f$, we can, with an MDS calculation, try to create \f$M\f$ projections, -\f$\mathbf{x}\f$, of the high dimensionality points in a \f$d\f$-dimensional linear space by trying to arrange the projections so that the +Multidimensional scaling (MDS) is similar to what is done when you make a map. You start with distances +between London, Belfast, Paris and Dublin and then you try to arrange points on a piece of paper so that the (suitably scaled) +distances between the points in your map representing each of those cities are related to the true distances between the cities. +Stating this more mathematically MDS endeavors to find an <a href="http://en.wikipedia.org/wiki/Isometry">isometry</a> +between points distributed in a high-dimensional space and a set of points distributed in a low-dimensional plane. +In other words, if we have \f$M\f$ \f$D\f$-dimensional points, \f$\mathbf{X}\f$, +and we can calculate dissimilarities between pairs them, \f$D_{ij}\f$, we can, with an MDS calculation, try to create \f$M\f$ projections, +\f$\mathbf{x}\f$, of the high dimensionality points in a \f$d\f$-dimensional linear space by trying to arrange the projections so that the Euclidean distances between pairs of them, \f$d_{ij}\f$, resemble the dissimilarities between the high dimensional points. In short we minimize: \f[ \chi^2 = \sum_{i \ne j} \left( D_{ij} - d_{ij} \right)^2 \f] -where \f$D_{ij}\f$ is the distance between point \f$X^{i}\f$ and point \f$X^{j}\f$ and \f$d_{ij}\f$ is the distance between the projection -of \f$X^{i}\f$, \f$x^i\f$, and the projection of \f$X^{j}\f$, \f$x^j\f$. A tutorial on this approach can be used to analyse simulations -can be found in the tutorial \ref belfast-3 and in the following <a href="https://www.youtube.com/watch?v=ofC2qz0_9_A&feature=youtu.be" > short video.</a> +where \f$D_{ij}\f$ is the distance between point \f$X^{i}\f$ and point \f$X^{j}\f$ and \f$d_{ij}\f$ is the distance between the projection +of \f$X^{i}\f$, \f$x^i\f$, and the projection of \f$X^{j}\f$, \f$x^j\f$. A tutorial on this approach can be used to analyse simulations +can be found in the tutorial \ref belfast-3 and in the following <a href="https://www.youtube.com/watch?v=ofC2qz0_9_A&feature=youtu.be" > short video.</a> \par Examples @@ -58,34 +58,34 @@ The RMSD distance between atoms 1-256 have moved is used to measure the distance \verbatim CLASSICAL_MDS ... ATOMS=1-256 - METRIC=OPTIMAL-FAST + METRIC=OPTIMAL-FAST USE_ALL_DATA NLOW_DIM=2 OUTPUT_FILE=rmsd-embed ... CLASSICAL_MDS \endverbatim -The following section is for people who are interested in how this method works in detail. A solid understanding of this material is -not necessary to use MDS. +The following section is for people who are interested in how this method works in detail. A solid understanding of this material is +not necessary to use MDS. \section dim-sec Method of optimisation -The stress function can be minimized using a standard optimization algorithm such as conjugate gradients or steepest descent. -However, it is more common to do this minimization using a technique known as classical scaling. Classical scaling works by +The stress function can be minimized using a standard optimization algorithm such as conjugate gradients or steepest descent. +However, it is more common to do this minimization using a technique known as classical scaling. Classical scaling works by recognizing that each of the distances $D_{ij}$ in the above sum can be written as: \f[ -D_{ij}^2 = \sum_{\alpha} (X^i_\alpha - X^j_\alpha)^2 = \sum_\alpha (X^i_\alpha)^2 + (X^j_\alpha)^2 - 2X^i_\alpha X^j_\alpha +D_{ij}^2 = \sum_{\alpha} (X^i_\alpha - X^j_\alpha)^2 = \sum_\alpha (X^i_\alpha)^2 + (X^j_\alpha)^2 - 2X^i_\alpha X^j_\alpha \f] -We can use this expression and matrix algebra to calculate multiple distances at once. For instance if we have three points, +We can use this expression and matrix algebra to calculate multiple distances at once. For instance if we have three points, \f$\mathbf{X}\f$, we can write distances between them as: \f{eqnarray*}{ D^2(\mathbf{X}) &=& \left[ \begin{array}{ccc} 0 & d_{12}^2 & d_{13}^2 \\ d_{12}^2 & 0 & d_{23}^2 \\ -d_{13}^2 & d_{23}^2 & 0 +d_{13}^2 & d_{23}^2 & 0 \end{array}\right] \\ &=& \sum_\alpha \left[ \begin{array}{ccc} @@ -103,19 +103,19 @@ X^1_\alpha X^1_\alpha & X^1_\alpha X^2_\alpha & X^1_\alpha X^3_\alpha \\ X^2_\alpha X^1_\alpha & X^2_\alpha X^2_\alpha & X^2_\alpha X^3_\alpha \\ X^1_\alpha X^3_\alpha & X^3_\alpha X^2_\alpha & X^3_\alpha X^3_\alpha \end{array}\right] \nonumber \\ -&=& \mathbf{c 1^T} + \mathbf{1 c^T} - 2 \sum_\alpha \mathbf{x}_a \mathbf{x}^T_a = \mathbf{c 1^T} + \mathbf{1 c^T} - 2\mathbf{X X^T} +&=& \mathbf{c 1^T} + \mathbf{1 c^T} - 2 \sum_\alpha \mathbf{x}_a \mathbf{x}^T_a = \mathbf{c 1^T} + \mathbf{1 c^T} - 2\mathbf{X X^T} \f} -This last equation can be extended to situations when we have more than three points. In it \f$\mathbf{X}\f$ is a matrix that has -one high-dimensional point on each of its rows and \f$\mathbf{X^T}\f$ is its transpose. \f$\mathbf{1}\f$ is an \f$M \times 1\f$ vector +This last equation can be extended to situations when we have more than three points. In it \f$\mathbf{X}\f$ is a matrix that has +one high-dimensional point on each of its rows and \f$\mathbf{X^T}\f$ is its transpose. \f$\mathbf{1}\f$ is an \f$M \times 1\f$ vector of ones and \f$\mathbf{c}\f$ is a vector with components given by: \f[ c_i = \sum_\alpha (x_\alpha^i)^2 \f] -These quantities are the diagonal elements of \f$\mathbf{X X^T}\f$, which is a dot product or Gram Matrix that contains the -dot product of the vector \f$X_i\f$ with the vector \f$X_j\f$ in element \f$i,j\f$. +These quantities are the diagonal elements of \f$\mathbf{X X^T}\f$, which is a dot product or Gram Matrix that contains the +dot product of the vector \f$X_i\f$ with the vector \f$X_j\f$ in element \f$i,j\f$. In classical scaling we introduce a centering matrix \f$\mathbf{J}\f$ that is given by: @@ -130,36 +130,36 @@ where \f$\mathbf{I}\f$ is the identity. Multiplying the equations above from th &=& -\frac{1}{2}\mathbf{J c 1^T J} - \frac{1}{2} \mathbf{J 1 c^T J} + \frac{1}{2} \mathbf{J}(2\mathbf{X X^T})\mathbf{J} \\ &=& \mathbf{ J X X^T J } = \mathbf{X X^T } \label{eqn:scaling} \f} - -The fist two terms in this expression disappear because \f$\mathbf{1^T J}=\mathbf{J 1} =\mathbf{0}\f$, where \f$\mathbf{0}\f$ -is a matrix containing all zeros. In the final step meanwhile we use the fact that the matrix of squared distances will not + +The fist two terms in this expression disappear because \f$\mathbf{1^T J}=\mathbf{J 1} =\mathbf{0}\f$, where \f$\mathbf{0}\f$ +is a matrix containing all zeros. In the final step meanwhile we use the fact that the matrix of squared distances will not change when we translate all the points. We can thus assume that the mean value, \f$\mu\f$, for each of the components, \f$\alpha\f$: \f[ \mu_\alpha = \frac{1}{M} \sum_{i=1}^N \mathbf{X}^i_\alpha \f] -is equal to 0 so the columns of \f$\mathbf{X}\f$ add up to 0. This in turn means that each of the columns of -\f$\mathbf{X X^T}\f$ adds up to zero, which is what allows us to write \f$\mathbf{ J X X^T J } = \mathbf{X X^T }\f$. +is equal to 0 so the columns of \f$\mathbf{X}\f$ add up to 0. This in turn means that each of the columns of +\f$\mathbf{X X^T}\f$ adds up to zero, which is what allows us to write \f$\mathbf{ J X X^T J } = \mathbf{X X^T }\f$. -The matrix of squared distances is symmetric and positive-definite we can thus use the spectral decomposition to decompose it as: +The matrix of squared distances is symmetric and positive-definite we can thus use the spectral decomposition to decompose it as: \f[ \Phi= \mathbf{V} \Lambda \mathbf{V}^T \f] -Furthermore, because the matrix we are diagonalizing, \f$\mathbf{X X^T}\f$, is the product of a matrix and its transpose +Furthermore, because the matrix we are diagonalizing, \f$\mathbf{X X^T}\f$, is the product of a matrix and its transpose we can use this decomposition to write: \f[ -\mathbf{X} =\mathbf{V} \Lambda^\frac{1}{2} +\mathbf{X} =\mathbf{V} \Lambda^\frac{1}{2} \f] -Much as in PCA there are generally a small number of large eigenvalues in \f$\Lambda\f$ and many small eigenvalues. -We can safely use only the large eigenvalues and their corresponding eigenvectors to express the relationship between -the coordinates \f$\mathbf{X}\f$. This gives us our set of low-dimensional projections. +Much as in PCA there are generally a small number of large eigenvalues in \f$\Lambda\f$ and many small eigenvalues. +We can safely use only the large eigenvalues and their corresponding eigenvectors to express the relationship between +the coordinates \f$\mathbf{X}\f$. This gives us our set of low-dimensional projections. This derivation makes a number of assumptions about the how the low dimensional points should best be arranged to minimise -the stress. If you use an interative optimization algorithm such as SMACOF you may thus be able to find a better -(lower-stress) projection of the points. For more details on the assumptions made +the stress. If you use an interative optimization algorithm such as SMACOF you may thus be able to find a better +(lower-stress) projection of the points. For more details on the assumptions made see <a href="http://quest4rigor.com/tag/multidimensional-scaling/"> this website.</a> */ //+ENDPLUMEDOC @@ -179,7 +179,7 @@ public: PLUMED_REGISTER_ACTION(ClassicalMultiDimensionalScaling,"CLASSICAL_MDS") -void ClassicalMultiDimensionalScaling::registerKeywords( Keywords& keys ){ +void ClassicalMultiDimensionalScaling::registerKeywords( Keywords& keys ) { AnalysisWithLandmarks::registerKeywords( keys ); keys.add("compulsory","NLOW_DIM","number of low-dimensional coordinates required"); keys.add("compulsory","OUTPUT_FILE","file on which to output the final embedding coordinates"); @@ -187,8 +187,8 @@ void ClassicalMultiDimensionalScaling::registerKeywords( Keywords& keys ){ } ClassicalMultiDimensionalScaling::ClassicalMultiDimensionalScaling( const ActionOptions& ao ): -Action(ao), -AnalysisWithLandmarks(ao) + Action(ao), + AnalysisWithLandmarks(ao) { myembedding = new PointWiseMapping( getMetricName(), false ); setDataToAnalyze( dynamic_cast<MultiReferenceBase*>(myembedding) ); @@ -196,10 +196,10 @@ AnalysisWithLandmarks(ao) parse("NLOW_DIM",nlow); if( nlow<1 ) error("dimensionality of low dimensional space must be at least one"); std::vector<std::string> propnames( nlow ); std::string num; - for(unsigned i=0;i<propnames.size();++i){ - Tools::convert(i+1,num); std::string lab=getLabel(); - if(lab.find("@")!=std::string::npos) propnames[i]=getName() + "." + num; - else propnames[i]=getLabel() + "." + num; + for(unsigned i=0; i<propnames.size(); ++i) { + Tools::convert(i+1,num); std::string lab=getLabel(); + if(lab.find("@")!=std::string::npos) propnames[i]=getName() + "." + num; + else propnames[i]=getLabel() + "." + num; } myembedding->setPropertyNames( propnames, false ); @@ -207,11 +207,11 @@ AnalysisWithLandmarks(ao) parseOutputFile("OUTPUT_FILE",ofilename); } -ClassicalMultiDimensionalScaling::~ClassicalMultiDimensionalScaling(){ +ClassicalMultiDimensionalScaling::~ClassicalMultiDimensionalScaling() { delete myembedding; } -void ClassicalMultiDimensionalScaling::analyzeLandmarks(){ +void ClassicalMultiDimensionalScaling::analyzeLandmarks() { // Calculate all pairwise diatances myembedding->calculateAllDistances( getPbc(), getArguments(), comm, myembedding->modifyDmat(), true ); @@ -220,27 +220,27 @@ void ClassicalMultiDimensionalScaling::analyzeLandmarks(){ // Output the embedding as long lists of data // std::string gfname=saveResultsFromPreviousAnalyses( ofilename ); - OFile gfile; gfile.link(*this); + OFile gfile; gfile.link(*this); gfile.setBackupString("analysis"); gfile.fmtField(getOutputFormat()+" "); gfile.open( ofilename.c_str() ); - + // Print embedding coordinates - for(unsigned i=0;i<myembedding->getNumberOfReferenceFrames();++i){ - for(unsigned j=0;j<nlow;++j){ - std::string num; Tools::convert(j+1,num); - gfile.printField( getLabel() + "." + num , myembedding->getProjectionCoordinate(i,j) ); - } - gfile.printField(); - } + for(unsigned i=0; i<myembedding->getNumberOfReferenceFrames(); ++i) { + for(unsigned j=0; j<nlow; ++j) { + std::string num; Tools::convert(j+1,num); + gfile.printField( getLabel() + "." + num, myembedding->getProjectionCoordinate(i,j) ); + } + gfile.printField(); + } gfile.close(); // Output the embedding in plumed format - if( efilename!="dont output"){ - OFile afile; afile.link(*this); afile.setBackupString("analysis"); - afile.open( efilename.c_str() ); - myembedding->print( "classical mds", getTime(), afile, getOutputFormat(), atoms.getUnits().getLength()/0.1 ); - afile.close(); + if( efilename!="dont output") { + OFile afile; afile.link(*this); afile.setBackupString("analysis"); + afile.open( efilename.c_str() ); + myembedding->print( "classical mds", getTime(), afile, getOutputFormat(), atoms.getUnits().getLength()/0.1 ); + afile.close(); } } diff --git a/src/analysis/ClassicalScaling.cpp b/src/analysis/ClassicalScaling.cpp index f7e9890c9..e7c911eee 100644 --- a/src/analysis/ClassicalScaling.cpp +++ b/src/analysis/ClassicalScaling.cpp @@ -25,31 +25,31 @@ namespace PLMD { namespace analysis { -void ClassicalScaling::run( PointWiseMapping* mymap ){ - // Retrieve the distances from the dimensionality reduction object - double half=(-0.5); Matrix<double> distances( half*mymap->modifyDmat() ); - - // Apply centering transtion - unsigned n=distances.nrows(); double sum; - // First HM - for(unsigned i=0;i<n;++i){ - sum=0; for(unsigned j=0;j<n;++j) sum+=distances(i,j); - for(unsigned j=0;j<n;++j) distances(i,j) -= sum/n; - } - // Now (HM)H - for(unsigned i=0;i<n;++i){ - sum=0; for(unsigned j=0;j<n;++j) sum+=distances(j,i); - for(unsigned j=0;j<n;++j) distances(j,i) -= sum/n; - } - - // Diagonalize matrix - std::vector<double> eigval(n); Matrix<double> eigvec(n,n); - diagMat( distances, eigval, eigvec ); - - // Pass final projections to map object - for(unsigned i=0;i<n;++i){ - for(unsigned j=0;j<mymap->getNumberOfProperties();++j) mymap->setProjectionCoordinate( i, j, sqrt(eigval[n-1-j])*eigvec(n-1-j,i) ); - } +void ClassicalScaling::run( PointWiseMapping* mymap ) { + // Retrieve the distances from the dimensionality reduction object + double half=(-0.5); Matrix<double> distances( half*mymap->modifyDmat() ); + + // Apply centering transtion + unsigned n=distances.nrows(); double sum; + // First HM + for(unsigned i=0; i<n; ++i) { + sum=0; for(unsigned j=0; j<n; ++j) sum+=distances(i,j); + for(unsigned j=0; j<n; ++j) distances(i,j) -= sum/n; + } + // Now (HM)H + for(unsigned i=0; i<n; ++i) { + sum=0; for(unsigned j=0; j<n; ++j) sum+=distances(j,i); + for(unsigned j=0; j<n; ++j) distances(j,i) -= sum/n; + } + + // Diagonalize matrix + std::vector<double> eigval(n); Matrix<double> eigvec(n,n); + diagMat( distances, eigval, eigvec ); + + // Pass final projections to map object + for(unsigned i=0; i<n; ++i) { + for(unsigned j=0; j<mymap->getNumberOfProperties(); ++j) mymap->setProjectionCoordinate( i, j, sqrt(eigval[n-1-j])*eigvec(n-1-j,i) ); + } } } diff --git a/src/analysis/Commit.cpp b/src/analysis/Commit.cpp index 6c9bf69c8..5cbacf4db 100644 --- a/src/analysis/Commit.cpp +++ b/src/analysis/Commit.cpp @@ -28,52 +28,52 @@ namespace PLMD { namespace analysis { -//+PLUMEDOC PRINTANALYSIS COMMITTOR +//+PLUMEDOC PRINTANALYSIS COMMITTOR /* Does a committor analysis. \par Examples The following input monitors two torsional angles during a simulation, -defines two basins (A and B) as a function of the two torsions and +defines two basins (A and B) as a function of the two torsions and stops the simulation when it falls in one of the two. In the log -file will be shown the latest values for the CVs and the basin reached. +file will be shown the latest values for the CVs and the basin reached. \verbatim TORSION ATOMS=1,2,3,4 LABEL=r1 TORSION ATOMS=2,3,4,5 LABEL=r2 COMMITTOR ... - ARG=r1,r2 + ARG=r1,r2 STRIDE=10 - BASIN_LL1=0.15,0.20 - BASIN_UL1=0.25,0.40 - BASIN_LL2=-0.15,-0.20 - BASIN_UL2=-0.25,-0.40 -... COMMITTOR + BASIN_LL1=0.15,0.20 + BASIN_UL1=0.25,0.40 + BASIN_LL2=-0.15,-0.20 + BASIN_UL2=-0.25,-0.40 +... COMMITTOR \endverbatim */ //+ENDPLUMEDOC -class Committor : -public ActionPilot, -public ActionWithArguments +class Committor : + public ActionPilot, + public ActionWithArguments { private: std::string file; OFile ofile; std::string fmt; - std::vector< std::vector<double> > lowerlimits; + std::vector< std::vector<double> > lowerlimits; std::vector< std::vector<double> > upperlimits; unsigned nbasins; public: static void registerKeywords( Keywords& keys ); explicit Committor(const ActionOptions&ao); void calculate(); - void apply(){} + void apply() {} }; PLUMED_REGISTER_ACTION(Committor,"COMMITTOR") -void Committor::registerKeywords( Keywords& keys ){ +void Committor::registerKeywords( Keywords& keys ) { Action::registerKeywords(keys); ActionPilot::registerKeywords(keys); ActionWithArguments::registerKeywords(keys); @@ -87,14 +87,14 @@ void Committor::registerKeywords( Keywords& keys ){ } Committor::Committor(const ActionOptions&ao): -Action(ao), -ActionPilot(ao), -ActionWithArguments(ao), -fmt("%f") + Action(ao), + ActionPilot(ao), + ActionWithArguments(ao), + fmt("%f") { ofile.link(*this); parse("FILE",file); - if(file.length()>0){ + if(file.length()>0) { ofile.open(file); log.printf(" on file %s\n",file.c_str()); } else { @@ -105,53 +105,53 @@ fmt("%f") fmt=" "+fmt; log.printf(" with format %s\n",fmt.c_str()); - for(unsigned i=0;i<getNumberOfArguments();++i) ofile.setupPrintValue( getPntrToArgument(i) ); + for(unsigned i=0; i<getNumberOfArguments(); ++i) ofile.setupPrintValue( getPntrToArgument(i) ); - for(unsigned b=1;;++b ){ + for(unsigned b=1;; ++b ) { - std::vector<double> tmpl, tmpu; - parseNumberedVector("BASIN_LL", b, tmpl ); - parseNumberedVector("BASIN_UL", b, tmpu ); - if( tmpl.empty() && tmpu.empty() ) break; - if( tmpl.size()!=getNumberOfArguments()) error("Wrong number of values for BASIN_LL: they should be equal to the number of arguments"); - if( tmpu.size()!=getNumberOfArguments()) error("Wrong number of values for BASIN_UL: they should be equal to the number of arguments"); - lowerlimits.push_back(tmpl); - upperlimits.push_back(tmpu); - nbasins=b; + std::vector<double> tmpl, tmpu; + parseNumberedVector("BASIN_LL", b, tmpl ); + parseNumberedVector("BASIN_UL", b, tmpu ); + if( tmpl.empty() && tmpu.empty() ) break; + if( tmpl.size()!=getNumberOfArguments()) error("Wrong number of values for BASIN_LL: they should be equal to the number of arguments"); + if( tmpu.size()!=getNumberOfArguments()) error("Wrong number of values for BASIN_UL: they should be equal to the number of arguments"); + lowerlimits.push_back(tmpl); + upperlimits.push_back(tmpu); + nbasins=b; } checkRead(); - for(unsigned b=0;b<nbasins;b++) { + for(unsigned b=0; b<nbasins; b++) { log.printf(" BASIN %u definition:\n", b+1); - for(unsigned i=0;i<getNumberOfArguments();++i){ + for(unsigned i=0; i<getNumberOfArguments(); ++i) { if(lowerlimits[b][i]>upperlimits[b][i]) error("COMMITTOR: UPPER bounds must always be greater than LOWER bounds"); log.printf(" %f - %f\n", lowerlimits[b][i], upperlimits[b][i]); } } } -void Committor::calculate(){ +void Committor::calculate() { std::vector<unsigned> inbasin; inbasin.assign (nbasins,1); - for(unsigned b=0;b<nbasins;++b){ - for(unsigned i=0;i<getNumberOfArguments();++i){ - if(getArgument(i)>lowerlimits[b][i]&&getArgument(i)<upperlimits[b][i]) inbasin[b]*=1; else inbasin[b]*=0; + for(unsigned b=0; b<nbasins; ++b) { + for(unsigned i=0; i<getNumberOfArguments(); ++i) { + if(getArgument(i)>lowerlimits[b][i]&&getArgument(i)<upperlimits[b][i]) inbasin[b]*=1; else inbasin[b]*=0; } } - for(unsigned b=0;b<nbasins;++b){ + for(unsigned b=0; b<nbasins; ++b) { if(inbasin[b]==1) { ofile.fmtField(" %f"); ofile.printField("time",getTime()); - for(unsigned i=0;i<getNumberOfArguments();i++){ + for(unsigned i=0; i<getNumberOfArguments(); i++) { ofile.fmtField(fmt); ofile.printField( getPntrToArgument(i), getArgument(i) ); } ofile.printField(); std::string num; Tools::convert( b+1, num ); - std::string str = "COMMITED TO BASIN " + num; + std::string str = "COMMITED TO BASIN " + num; ofile.addConstantField(str); ofile.printField(); ofile.flush(); diff --git a/src/analysis/Histogram.cpp b/src/analysis/Histogram.cpp index 5a92cdaa0..b8a74c797 100644 --- a/src/analysis/Histogram.cpp +++ b/src/analysis/Histogram.cpp @@ -28,14 +28,14 @@ #include "core/PlumedMain.h" #include "core/ActionSet.h" -namespace PLMD{ -namespace analysis{ +namespace PLMD { +namespace analysis { //+PLUMEDOC GRIDCALC HISTOGRAM -/* +/* Accumulate the average probability density along a few CVs from a trajectory. -When using this method it is supposed that you have some collective variable \f$\zeta\f$ that +When using this method it is supposed that you have some collective variable \f$\zeta\f$ that gives a reasonable description of some physical or chemical phenomenon. As an example of what we mean by this suppose you wish to examine the following SN2 reaction: @@ -45,7 +45,7 @@ mean by this suppose you wish to examine the following SN2 reaction: The distance between the chlorine atom and the carbon is an excellent collective variable, \f$\zeta\f$, in this case because this distance is short for the reactant, \f$\textrm{CH}_3Cl\f$, because the carbon -and chlorine are chemically bonded, and because it is long for the product state when these two atoms are +and chlorine are chemically bonded, and because it is long for the product state when these two atoms are not chemically bonded. We thus might want to accumulate the probability density, \f$P(\zeta)\f$, as a function of this distance as this will provide us with information about the overall likelihood of the reaction. Furthermore, the free energy, \f$F(\zeta)\f$, is related to this probability density via: @@ -54,8 +54,8 @@ free energy, \f$F(\zeta)\f$, is related to this probability density via: F(\zeta) = - k_B T \ln P(\zeta) \f] -Accumulating these probability densities is precisely what this Action can be used to do. Furthermore, the conversion -of the histogram to the free energy can be achieved by using the method \ref CONVERT_TO_FES. +Accumulating these probability densities is precisely what this Action can be used to do. Furthermore, the conversion +of the histogram to the free energy can be achieved by using the method \ref CONVERT_TO_FES. We calculate histograms within PLUMED using a method known as kernel density estimation, which you can read more about here: @@ -66,20 +66,20 @@ centered at the current value, \f$\zeta(t)\f$, of this quantity is generated wit is set by the user. These kernels are then used to accumulate the ensemble average for the probability density: \f[ -\langle P(\zeta) \rangle = \frac{ \sum_{t'=0}^t w(t') K(\zeta-\zeta(t'),\sigma) }{ \sum_{t'=0}^t w(t') } -\f] +\langle P(\zeta) \rangle = \frac{ \sum_{t'=0}^t w(t') K(\zeta-\zeta(t'),\sigma) }{ \sum_{t'=0}^t w(t') } +\f] -Here the sums run over a portion of the trajectory specified by the user. The final quantity evalulated is a weighted -average as the weights, \f$w(t')\f$, allow us to negate the effect any bias might have on the region of phase space +Here the sums run over a portion of the trajectory specified by the user. The final quantity evalulated is a weighted +average as the weights, \f$w(t')\f$, allow us to negate the effect any bias might have on the region of phase space sampled by the system. This is discussed in the section of the manual on \ref Analysis. A discrete analogue of kernel density estimation can also be used. In this analogue the kernels in the above formula are replaced by dirac delta functions. When this method is used the final function calculated is no longer a probability -density - it is instead a probability mass function as each element of the function tells you the value of an integral -between two points on your grid rather than the value of a (continuous) function on a grid. +density - it is instead a probability mass function as each element of the function tells you the value of an integral +between two points on your grid rather than the value of a (continuous) function on a grid. + +Additional material and examples can be also found in the tutorial \ref belfast-1. -Additional material and examples can be also found in the tutorial \ref belfast-1. - \par Examples The following input monitors two torsional angles during a simulation @@ -88,11 +88,11 @@ and outputs a continuos histogram as a function of them at the end of the simula TORSION ATOMS=1,2,3,4 LABEL=r1 TORSION ATOMS=2,3,4,5 LABEL=r2 HISTOGRAM ... - ARG=r1,r2 - GRID_MIN=-3.14,-3.14 - GRID_MAX=3.14,3.14 + ARG=r1,r2 + GRID_MIN=-3.14,-3.14 + GRID_MAX=3.14,3.14 GRID_BIN=200,200 - BANDWIDTH=0.05,0.05 + BANDWIDTH=0.05,0.05 LABEL=hh ... HISTOGRAM @@ -105,11 +105,11 @@ and outputs a discrete histogram as a function of them at the end of the simulat TORSION ATOMS=1,2,3,4 LABEL=r1 TORSION ATOMS=2,3,4,5 LABEL=r2 HISTOGRAM ... - ARG=r1,r2 + ARG=r1,r2 USE_ALL_DATA KERNEL=DISCRETE - GRID_MIN=-3.14,-3.14 - GRID_MAX=3.14,3.14 + GRID_MIN=-3.14,-3.14 + GRID_MAX=3.14,3.14 GRID_BIN=200,200 LABEL=hh ... HISTOGRAM @@ -123,11 +123,11 @@ and outputs the histogram accumulated thus far every 100000 steps. TORSION ATOMS=1,2,3,4 LABEL=r1 TORSION ATOMS=2,3,4,5 LABEL=r2 HISTOGRAM ... - ARG=r1,r2 - GRID_MIN=-3.14,-3.14 - GRID_MAX=3.14,3.14 + ARG=r1,r2 + GRID_MIN=-3.14,-3.14 + GRID_MAX=3.14,3.14 GRID_BIN=200,200 - BANDWIDTH=0.05,0.05 + BANDWIDTH=0.05,0.05 LABEL=hh ... HISTOGRAM @@ -136,18 +136,18 @@ DUMPGRID GRID=hh FILE=histo STRIDE=100000 The following input monitors two torsional angles during a simulation and outputs a separate histogram for each 100000 steps worth of trajectory. -Notice how the CLEAR keyword is used here and how it is not used in the +Notice how the CLEAR keyword is used here and how it is not used in the previous example. \verbatim TORSION ATOMS=1,2,3,4 LABEL=r1 TORSION ATOMS=2,3,4,5 LABEL=r2 HISTOGRAM ... - ARG=r1,r2 CLEAR=100000 - GRID_MIN=-3.14,-3.14 - GRID_MAX=3.14,3.14 + ARG=r1,r2 CLEAR=100000 + GRID_MIN=-3.14,-3.14 + GRID_MAX=3.14,3.14 GRID_BIN=200,200 - BANDWIDTH=0.05,0.05 + BANDWIDTH=0.05,0.05 GRID_WFILE=histo LABEL=hh ... HISTOGRAM @@ -158,7 +158,7 @@ DUMPGRID GRID=hh FILE=histo STRIDE=100000 */ //+ENDPLUMEDOC -class Histogram : public gridtools::ActionWithGrid { +class Histogram : public gridtools::ActionWithGrid { private: double ww; bool in_apply, mvectors; @@ -166,7 +166,7 @@ private: std::vector<double> forcesToApply, finalForces; std::vector<vesselbase::ActionWithVessel*> myvessels; std::vector<vesselbase::StoreDataVessel*> stashes; - gridtools::HistogramOnGrid* myhist; + gridtools::HistogramOnGrid* myhist; public: static void registerKeywords( Keywords& keys ); explicit Histogram(const ActionOptions&ao); @@ -174,16 +174,16 @@ public: void prepareForAveraging(); void performOperations( const bool& from_update ); void finishAveraging(); - bool isPeriodic(){ return false; } - unsigned getNumberOfDerivatives(); + bool isPeriodic() { return false; } + unsigned getNumberOfDerivatives(); void turnOnDerivatives(); - void compute( const unsigned& , MultiValue& ) const ; + void compute( const unsigned&, MultiValue& ) const ; void apply(); }; PLUMED_REGISTER_ACTION(Histogram,"HISTOGRAM") -void Histogram::registerKeywords( Keywords& keys ){ +void Histogram::registerKeywords( Keywords& keys ) { gridtools::ActionWithGrid::registerKeywords( keys ); keys.use("ARG"); keys.add("optional","DATA","input data from action with vessel and compute histogram"); keys.add("optional","VECTORS","input three dimsnional vectors for computing histogram"); @@ -195,137 +195,137 @@ void Histogram::registerKeywords( Keywords& keys ){ } Histogram::Histogram(const ActionOptions&ao): -Action(ao), -ActionWithGrid(ao), -ww(0.0), -in_apply(false), -mvectors(false), -kernel(NULL) + Action(ao), + ActionWithGrid(ao), + ww(0.0), + in_apply(false), + mvectors(false), + kernel(NULL) { - // Read in arguments + // Read in arguments std::string vlab; parse("VECTORS",vlab); - if( vlab.length()>0 ){ - ActionWithVessel* myv = plumed.getActionSet().selectWithLabel<ActionWithVessel*>( vlab ); - if( !myv ) error("action labelled " + vlab + " does not exist or is not an ActionWithVessel"); - myvessels.push_back( myv ); stashes.push_back( myv->buildDataStashes( NULL ) ); - addDependency( myv ); mvectors=true; - if( myv->getNumberOfQuantities()!=5 ) error("can only compute histograms for three dimensional vectors"); - log.printf(" for vector quantities calculated by %s \n", vlab.c_str() ); + if( vlab.length()>0 ) { + ActionWithVessel* myv = plumed.getActionSet().selectWithLabel<ActionWithVessel*>( vlab ); + if( !myv ) error("action labelled " + vlab + " does not exist or is not an ActionWithVessel"); + myvessels.push_back( myv ); stashes.push_back( myv->buildDataStashes( NULL ) ); + addDependency( myv ); mvectors=true; + if( myv->getNumberOfQuantities()!=5 ) error("can only compute histograms for three dimensional vectors"); + log.printf(" for vector quantities calculated by %s \n", vlab.c_str() ); } else { - std::vector<std::string> mlab; parseVector("DATA",mlab); - if( mlab.size()>0 ){ - for(unsigned i=0;i<mlab.size();++i){ - ActionWithVessel* myv = plumed.getActionSet().selectWithLabel<ActionWithVessel*>( mlab[i] ); - if( !myv ) error("action labelled " + mlab[i] + " does not exist or is not an ActionWithVessel"); - myvessels.push_back( myv ); stashes.push_back( myv->buildDataStashes( NULL ) ); - // log.printf(" for all base quantities calculated by %s \n",myvessel->getLabel().c_str() ); - // Add the dependency - addDependency( myv ); - } - unsigned nvals = myvessels[0]->getFullNumberOfTasks(); - for(unsigned i=1;i<mlab.size();++i){ - if( nvals!=myvessels[i]->getFullNumberOfTasks() ) error("mismatched number of quantities calculated by actions input to histogram"); - } - log.printf(" for all base quantities calculated by %s ", myvessels[0]->getLabel().c_str() ); - for(unsigned i=1;i<mlab.size();++i) log.printf(", %s \n", myvessels[i]->getLabel().c_str() ); + std::vector<std::string> mlab; parseVector("DATA",mlab); + if( mlab.size()>0 ) { + for(unsigned i=0; i<mlab.size(); ++i) { + ActionWithVessel* myv = plumed.getActionSet().selectWithLabel<ActionWithVessel*>( mlab[i] ); + if( !myv ) error("action labelled " + mlab[i] + " does not exist or is not an ActionWithVessel"); + myvessels.push_back( myv ); stashes.push_back( myv->buildDataStashes( NULL ) ); + // log.printf(" for all base quantities calculated by %s \n",myvessel->getLabel().c_str() ); + // Add the dependency + addDependency( myv ); + } + unsigned nvals = myvessels[0]->getFullNumberOfTasks(); + for(unsigned i=1; i<mlab.size(); ++i) { + if( nvals!=myvessels[i]->getFullNumberOfTasks() ) error("mismatched number of quantities calculated by actions input to histogram"); + } + log.printf(" for all base quantities calculated by %s ", myvessels[0]->getLabel().c_str() ); + for(unsigned i=1; i<mlab.size(); ++i) log.printf(", %s \n", myvessels[i]->getLabel().c_str() ); + log.printf("\n"); + } else { + std::vector<Value*> arg; parseArgumentList("ARG",arg); + if(!arg.empty()) { + log.printf(" with arguments"); + for(unsigned i=0; i<arg.size(); i++) log.printf(" %s",arg[i]->getName().c_str()); log.printf("\n"); - } else { - std::vector<Value*> arg; parseArgumentList("ARG",arg); - if(!arg.empty()){ - log.printf(" with arguments"); - for(unsigned i=0;i<arg.size();i++) log.printf(" %s",arg[i]->getName().c_str()); - log.printf("\n"); - // Retrieve the bias acting and make sure we request this also - std::vector<Value*> bias( ActionWithArguments::getArguments() ); - for(unsigned i=0;i<bias.size();++i) arg.push_back( bias[i] ); - requestArguments(arg); - } - } - } + // Retrieve the bias acting and make sure we request this also + std::vector<Value*> bias( ActionWithArguments::getArguments() ); + for(unsigned i=0; i<bias.size(); ++i) arg.push_back( bias[i] ); + requestArguments(arg); + } + } + } // Read stuff for grid unsigned narg = getNumberOfArguments(); if( myvessels.size()>0 ) narg=myvessels.size(); // Input of name and labels std::string vstring="COMPONENTS=" + getLabel(); - if( mvectors ){ - vstring += " COORDINATES=x,y,z PBC=F,F,F"; - } else if( myvessels.size()>0 ){ - vstring += " COORDINATES=" + myvessels[0]->getLabel(); - for(unsigned i=1;i<myvessels.size();++i) vstring +="," + myvessels[i]->getLabel(); - // Input for PBC - if( myvessels[0]->isPeriodic() ) vstring+=" PBC=T"; - else vstring+=" PBC=F"; - for(unsigned i=1;i<myvessels.size();++i){ - if( myvessels[i]->isPeriodic() ) vstring+=",T"; - else vstring+=",F"; - } + if( mvectors ) { + vstring += " COORDINATES=x,y,z PBC=F,F,F"; + } else if( myvessels.size()>0 ) { + vstring += " COORDINATES=" + myvessels[0]->getLabel(); + for(unsigned i=1; i<myvessels.size(); ++i) vstring +="," + myvessels[i]->getLabel(); + // Input for PBC + if( myvessels[0]->isPeriodic() ) vstring+=" PBC=T"; + else vstring+=" PBC=F"; + for(unsigned i=1; i<myvessels.size(); ++i) { + if( myvessels[i]->isPeriodic() ) vstring+=",T"; + else vstring+=",F"; + } } else { - vstring += " COORDINATES=" + getPntrToArgument(0)->getName(); - for(unsigned i=1;i<getNumberOfArguments();++i) vstring += "," + getPntrToArgument(i)->getName(); - // Input for PBC - if( getPntrToArgument(0)->isPeriodic() ) vstring+=" PBC=T"; - else vstring+=" PBC=F"; - for(unsigned i=1;i<getNumberOfArguments();++i){ - if( getPntrToArgument(i)->isPeriodic() ) vstring+=",T"; - else vstring+=",F"; - } + vstring += " COORDINATES=" + getPntrToArgument(0)->getName(); + for(unsigned i=1; i<getNumberOfArguments(); ++i) vstring += "," + getPntrToArgument(i)->getName(); + // Input for PBC + if( getPntrToArgument(0)->isPeriodic() ) vstring+=" PBC=T"; + else vstring+=" PBC=F"; + for(unsigned i=1; i<getNumberOfArguments(); ++i) { + if( getPntrToArgument(i)->isPeriodic() ) vstring+=",T"; + else vstring+=",F"; + } } // And create the grid - createGrid( "histogram", vstring ); - if( mygrid->getType()=="flat" ){ - if( mvectors ) error("computing histogram for three dimensional vectors but grid is not of fibonacci type - use CONCENTRATION"); - std::vector<std::string> gmin( narg ), gmax( narg ); - parseVector("GRID_MIN",gmin); parseVector("GRID_MAX",gmax); - std::vector<unsigned> nbin; parseVector("GRID_BIN",nbin); - std::vector<double> gspacing; parseVector("GRID_SPACING",gspacing); - if( nbin.size()!=narg && gspacing.size()!=narg ){ - error("GRID_BIN or GRID_SPACING must be set"); - } - mygrid->setBounds( gmin, gmax, nbin, gspacing ); + createGrid( "histogram", vstring ); + if( mygrid->getType()=="flat" ) { + if( mvectors ) error("computing histogram for three dimensional vectors but grid is not of fibonacci type - use CONCENTRATION"); + std::vector<std::string> gmin( narg ), gmax( narg ); + parseVector("GRID_MIN",gmin); parseVector("GRID_MAX",gmax); + std::vector<unsigned> nbin; parseVector("GRID_BIN",nbin); + std::vector<double> gspacing; parseVector("GRID_SPACING",gspacing); + if( nbin.size()!=narg && gspacing.size()!=narg ) { + error("GRID_BIN or GRID_SPACING must be set"); + } + mygrid->setBounds( gmin, gmax, nbin, gspacing ); } else { - std::vector<unsigned> nbin; parseVector("GRID_BIN",nbin); - if( nbin.size()!=1 ) error("should only be one index for number of bins with spherical grid"); - if( mygrid->getType()=="fibonacci" ) mygrid->setupFibonacciGrid( nbin[0] ); + std::vector<unsigned> nbin; parseVector("GRID_BIN",nbin); + if( nbin.size()!=1 ) error("should only be one index for number of bins with spherical grid"); + if( mygrid->getType()=="fibonacci" ) mygrid->setupFibonacciGrid( nbin[0] ); } - myhist = dynamic_cast<gridtools::HistogramOnGrid*>( mygrid ); - plumed_assert( myhist ); - if( myvessels.size()>0 ){ - // Create a task list - for(unsigned i=0;i<myvessels[0]->getFullNumberOfTasks();++i) addTaskToList(i); - setAveragingAction( mygrid, true ); + myhist = dynamic_cast<gridtools::HistogramOnGrid*>( mygrid ); + plumed_assert( myhist ); + if( myvessels.size()>0 ) { + // Create a task list + for(unsigned i=0; i<myvessels[0]->getFullNumberOfTasks(); ++i) addTaskToList(i); + setAveragingAction( mygrid, true ); } else { - // Create a task list - for(unsigned i=0;i<mygrid->getNumberOfPoints();++i) addTaskToList(i); - myhist->addOneKernelEachTimeOnly(); - setAveragingAction( mygrid, myhist->noDiscreteKernels() ); + // Create a task list + for(unsigned i=0; i<mygrid->getNumberOfPoints(); ++i) addTaskToList(i); + myhist->addOneKernelEachTimeOnly(); + setAveragingAction( mygrid, myhist->noDiscreteKernels() ); } checkRead(); } -void Histogram::turnOnDerivatives(){ +void Histogram::turnOnDerivatives() { ActionWithGrid::turnOnDerivatives(); std::vector<AtomNumber> all_atoms, tmp_atoms; - for(unsigned i=0;i<myvessels.size();++i){ - multicolvar::MultiColvarBase* mbase=dynamic_cast<multicolvar::MultiColvarBase*>( myvessels[i] ); - if( !mbase ) error("do not know how to get histogram derivatives for actions of type " + myvessels[i]->getName() ); - tmp_atoms = mbase->getAbsoluteIndexes(); - for(unsigned j=0;j<tmp_atoms.size();++j) all_atoms.push_back( tmp_atoms[j] ); + for(unsigned i=0; i<myvessels.size(); ++i) { + multicolvar::MultiColvarBase* mbase=dynamic_cast<multicolvar::MultiColvarBase*>( myvessels[i] ); + if( !mbase ) error("do not know how to get histogram derivatives for actions of type " + myvessels[i]->getName() ); + tmp_atoms = mbase->getAbsoluteIndexes(); + for(unsigned j=0; j<tmp_atoms.size(); ++j) all_atoms.push_back( tmp_atoms[j] ); } - ActionAtomistic::requestAtoms( all_atoms ); - finalForces.resize( 3*all_atoms.size() + 9 ); + ActionAtomistic::requestAtoms( all_atoms ); + finalForces.resize( 3*all_atoms.size() + 9 ); forcesToApply.resize( 3*all_atoms.size() + 9*myvessels.size() ); // And make sure we still have the dependencies which are cleared by requestAtoms - for(unsigned i=0;i<myvessels.size();++i) addDependency( myvessels[i] ); + for(unsigned i=0; i<myvessels.size(); ++i) addDependency( myvessels[i] ); // And resize the histogram so that we have a place to store the forces in_apply=true; mygrid->resize(); in_apply=false; } -unsigned Histogram::getNumberOfDerivatives(){ - if( in_apply ){ - unsigned nder=0; - for(unsigned i=0;i<myvessels.size();++i) nder += myvessels[i]->getNumberOfDerivatives(); - return nder; +unsigned Histogram::getNumberOfDerivatives() { + if( in_apply ) { + unsigned nder=0; + for(unsigned i=0; i<myvessels.size(); ++i) nder += myvessels[i]->getNumberOfDerivatives(); + return nder; } return getNumberOfArguments(); } @@ -336,152 +336,152 @@ unsigned Histogram::getNumberOfQuantities() const { return 2; } -void Histogram::prepareForAveraging(){ - if( myvessels.size()>0 ){ - deactivateAllTasks(); double norm=0; - for(unsigned i=0;i<stashes[0]->getNumberOfStoredValues();++i){ - std::vector<double> cvals( myvessels[0]->getNumberOfQuantities() ); - stashes[0]->retrieveSequentialValue( i, false, cvals ); - unsigned itask=myvessels[0]->getActiveTask(i); double tnorm = cvals[0]; - for(unsigned j=1;j<myvessels.size();++j){ - if( myvessels[j]->getActiveTask(i)!=itask ) error("mismatched task identities in histogram suggests histogram is meaningless"); - if( cvals.size()!=myvessels[j]->getNumberOfQuantities() ) cvals.resize( myvessels[j]->getNumberOfQuantities() ); - stashes[j]->retrieveSequentialValue( i, false, cvals ); tnorm *= cvals[0]; - } - norm += tnorm; taskFlags[i]=1; +void Histogram::prepareForAveraging() { + if( myvessels.size()>0 ) { + deactivateAllTasks(); double norm=0; + for(unsigned i=0; i<stashes[0]->getNumberOfStoredValues(); ++i) { + std::vector<double> cvals( myvessels[0]->getNumberOfQuantities() ); + stashes[0]->retrieveSequentialValue( i, false, cvals ); + unsigned itask=myvessels[0]->getActiveTask(i); double tnorm = cvals[0]; + for(unsigned j=1; j<myvessels.size(); ++j) { + if( myvessels[j]->getActiveTask(i)!=itask ) error("mismatched task identities in histogram suggests histogram is meaningless"); + if( cvals.size()!=myvessels[j]->getNumberOfQuantities() ) cvals.resize( myvessels[j]->getNumberOfQuantities() ); + stashes[j]->retrieveSequentialValue( i, false, cvals ); tnorm *= cvals[0]; } - lockContributors(); - // Sort out normalization of histogram - if( !noNormalization() ) ww = cweight / norm; - else ww = cweight; + norm += tnorm; taskFlags[i]=1; + } + lockContributors(); + // Sort out normalization of histogram + if( !noNormalization() ) ww = cweight / norm; + else ww = cweight; } else { - // Now fetch the kernel and the active points - std::vector<double> point( getNumberOfArguments() ); - for(unsigned i=0;i<point.size();++i) point[i]=getArgument(i); - unsigned num_neigh; std::vector<unsigned> neighbors(1); - kernel = myhist->getKernelAndNeighbors( point, num_neigh, neighbors ); - - if( num_neigh>1 ){ - // Activate relevant tasks - deactivateAllTasks(); - for(unsigned i=0;i<num_neigh;++i) taskFlags[neighbors[i]]=1; - lockContributors(); - } else { - // This is used when we are not doing kernel density evaluation - mygrid->addToGridElement( neighbors[0], 0, cweight ); - } + // Now fetch the kernel and the active points + std::vector<double> point( getNumberOfArguments() ); + for(unsigned i=0; i<point.size(); ++i) point[i]=getArgument(i); + unsigned num_neigh; std::vector<unsigned> neighbors(1); + kernel = myhist->getKernelAndNeighbors( point, num_neigh, neighbors ); + + if( num_neigh>1 ) { + // Activate relevant tasks + deactivateAllTasks(); + for(unsigned i=0; i<num_neigh; ++i) taskFlags[neighbors[i]]=1; + lockContributors(); + } else { + // This is used when we are not doing kernel density evaluation + mygrid->addToGridElement( neighbors[0], 0, cweight ); + } } } -void Histogram::performOperations( const bool& from_update ){ if( myvessels.size()==0 ) plumed_dbg_assert( !myhist->noDiscreteKernels() ); } +void Histogram::performOperations( const bool& from_update ) { if( myvessels.size()==0 ) plumed_dbg_assert( !myhist->noDiscreteKernels() ); } -void Histogram::finishAveraging(){ +void Histogram::finishAveraging() { if( myvessels.size()==0 ) delete kernel; } -void Histogram::compute( const unsigned& current, MultiValue& myvals ) const { - if( mvectors ){ - std::vector<double> cvals( myvessels[0]->getNumberOfQuantities() ); - stashes[0]->retrieveSequentialValue( current, true, cvals ); - for(unsigned i=2;i<myvessels[0]->getNumberOfQuantities();++i) myvals.setValue( i-1, cvals[i] ); - myvals.setValue( 0, cvals[0] ); myvals.setValue( myvessels[0]->getNumberOfQuantities() - 1, ww ); - if( in_apply ){ - MultiValue tmpval( myvessels[0]->getNumberOfQuantities(), myvessels[0]->getNumberOfDerivatives() ); - stashes[0]->retrieveDerivatives( stashes[0]->getTrueIndex(current), true, tmpval ); - for(unsigned j=0;j<tmpval.getNumberActive();++j){ - unsigned jder=tmpval.getActiveIndex(j); myvals.addDerivative( 0, jder, tmpval.getDerivative(0, jder) ); - for(unsigned i=2;i<myvessels[0]->getNumberOfQuantities();++i) myvals.addDerivative( i-1, jder, tmpval.getDerivative(i, jder) ); - } - myvals.updateDynamicList(); +void Histogram::compute( const unsigned& current, MultiValue& myvals ) const { + if( mvectors ) { + std::vector<double> cvals( myvessels[0]->getNumberOfQuantities() ); + stashes[0]->retrieveSequentialValue( current, true, cvals ); + for(unsigned i=2; i<myvessels[0]->getNumberOfQuantities(); ++i) myvals.setValue( i-1, cvals[i] ); + myvals.setValue( 0, cvals[0] ); myvals.setValue( myvessels[0]->getNumberOfQuantities() - 1, ww ); + if( in_apply ) { + MultiValue tmpval( myvessels[0]->getNumberOfQuantities(), myvessels[0]->getNumberOfDerivatives() ); + stashes[0]->retrieveDerivatives( stashes[0]->getTrueIndex(current), true, tmpval ); + for(unsigned j=0; j<tmpval.getNumberActive(); ++j) { + unsigned jder=tmpval.getActiveIndex(j); myvals.addDerivative( 0, jder, tmpval.getDerivative(0, jder) ); + for(unsigned i=2; i<myvessels[0]->getNumberOfQuantities(); ++i) myvals.addDerivative( i-1, jder, tmpval.getDerivative(i, jder) ); } - } else if( myvessels.size()>0 ){ - std::vector<double> cvals( myvessels[0]->getNumberOfQuantities() ); - stashes[0]->retrieveSequentialValue( current, false, cvals ); - unsigned derbase; double totweight=cvals[0], tnorm = cvals[0]; myvals.setValue( 1, cvals[1] ); - // Get the derivatives as well if we are in apply - if( in_apply ){ - // This bit gets the total weight - double weight0 = cvals[0]; // Store the current weight - for(unsigned j=1;j<myvessels.size();++j){ - stashes[j]->retrieveSequentialValue( current, false, cvals ); totweight *= cvals[0]; - } - // And this bit the derivatives - MultiValue tmpval( myvessels[0]->getNumberOfQuantities(), myvessels[0]->getNumberOfDerivatives() ); - stashes[0]->retrieveDerivatives( stashes[0]->getTrueIndex(current), false, tmpval ); - for(unsigned j=0;j<tmpval.getNumberActive();++j){ - unsigned jder=tmpval.getActiveIndex(j); - myvals.addDerivative( 1, jder, tmpval.getDerivative(1,jder) ); - myvals.addDerivative( 0, jder, (totweight/weight0)*tmpval.getDerivative(0,jder) ); - } - derbase = myvessels[0]->getNumberOfDerivatives(); + myvals.updateDynamicList(); + } + } else if( myvessels.size()>0 ) { + std::vector<double> cvals( myvessels[0]->getNumberOfQuantities() ); + stashes[0]->retrieveSequentialValue( current, false, cvals ); + unsigned derbase; double totweight=cvals[0], tnorm = cvals[0]; myvals.setValue( 1, cvals[1] ); + // Get the derivatives as well if we are in apply + if( in_apply ) { + // This bit gets the total weight + double weight0 = cvals[0]; // Store the current weight + for(unsigned j=1; j<myvessels.size(); ++j) { + stashes[j]->retrieveSequentialValue( current, false, cvals ); totweight *= cvals[0]; } - for(unsigned i=1;i<myvessels.size();++i){ - if( cvals.size()!=myvessels[i]->getNumberOfQuantities() ) cvals.resize( myvessels[i]->getNumberOfQuantities() ); - stashes[i]->retrieveSequentialValue( current, false, cvals ); - tnorm *= cvals[0]; myvals.setValue( 1+i, cvals[1] ); - // Get the derivatives as well if we are in apply - if( in_apply ){ - MultiValue tmpval( myvessels[i]->getNumberOfQuantities(), myvessels[i]->getNumberOfDerivatives() ); - stashes[i]->retrieveDerivatives( stashes[i]->getTrueIndex(current), false, tmpval ); - for(unsigned j=0;j<tmpval.getNumberActive();++j){ - unsigned jder=tmpval.getActiveIndex(j); - myvals.addDerivative( 1+i, derbase+jder, tmpval.getDerivative(1,jder) ); - myvals.addDerivative( 0, derbase+jder, (totweight/cvals[0])*tmpval.getDerivative(0,jder) ); - } - derbase += myvessels[i]->getNumberOfDerivatives(); - } + // And this bit the derivatives + MultiValue tmpval( myvessels[0]->getNumberOfQuantities(), myvessels[0]->getNumberOfDerivatives() ); + stashes[0]->retrieveDerivatives( stashes[0]->getTrueIndex(current), false, tmpval ); + for(unsigned j=0; j<tmpval.getNumberActive(); ++j) { + unsigned jder=tmpval.getActiveIndex(j); + myvals.addDerivative( 1, jder, tmpval.getDerivative(1,jder) ); + myvals.addDerivative( 0, jder, (totweight/weight0)*tmpval.getDerivative(0,jder) ); } - myvals.setValue( 0, tnorm ); myvals.setValue( 1+myvessels.size(), ww ); - if( in_apply ) myvals.updateDynamicList(); - } else { - plumed_assert( !in_apply ); - std::vector<Value*> vv( myhist->getVectorOfValues() ); - std::vector<double> val( getNumberOfArguments() ), der( getNumberOfArguments() ); - // Retrieve the location of the grid point at which we are evaluating the kernel - mygrid->getGridPointCoordinates( current, val ); - if( kernel ){ - for(unsigned i=0;i<getNumberOfArguments();++i) vv[i]->set( val[i] ); - // Evaluate the histogram at the relevant grid point and set the values - double vvh = kernel->evaluate( vv, der ,true); myvals.setValue( 1, vvh ); - } else { - plumed_merror("normalisation of vectors does not work with arguments and spherical grids"); - // Evalulate dot product - double dot=0; for(unsigned j=0;j<getNumberOfArguments();++j){ dot+=val[j]*getArgument(j); der[j]=val[j]; } - // Von misses distribution for concentration parameter - double newval = (myhist->von_misses_norm)*exp( (myhist->von_misses_concentration)*dot ); myvals.setValue( 1, newval ); - // And final derivatives - for(unsigned j=0;j<getNumberOfArguments();++j) der[j] *= (myhist->von_misses_concentration)*newval; + derbase = myvessels[0]->getNumberOfDerivatives(); + } + for(unsigned i=1; i<myvessels.size(); ++i) { + if( cvals.size()!=myvessels[i]->getNumberOfQuantities() ) cvals.resize( myvessels[i]->getNumberOfQuantities() ); + stashes[i]->retrieveSequentialValue( current, false, cvals ); + tnorm *= cvals[0]; myvals.setValue( 1+i, cvals[1] ); + // Get the derivatives as well if we are in apply + if( in_apply ) { + MultiValue tmpval( myvessels[i]->getNumberOfQuantities(), myvessels[i]->getNumberOfDerivatives() ); + stashes[i]->retrieveDerivatives( stashes[i]->getTrueIndex(current), false, tmpval ); + for(unsigned j=0; j<tmpval.getNumberActive(); ++j) { + unsigned jder=tmpval.getActiveIndex(j); + myvals.addDerivative( 1+i, derbase+jder, tmpval.getDerivative(1,jder) ); + myvals.addDerivative( 0, derbase+jder, (totweight/cvals[0])*tmpval.getDerivative(0,jder) ); + } + derbase += myvessels[i]->getNumberOfDerivatives(); } - // Set the derivatives and delete the vector of values - for(unsigned i=0;i<getNumberOfArguments();++i){ myvals.setDerivative( 1, i, der[i] ); delete vv[i]; } + } + myvals.setValue( 0, tnorm ); myvals.setValue( 1+myvessels.size(), ww ); + if( in_apply ) myvals.updateDynamicList(); + } else { + plumed_assert( !in_apply ); + std::vector<Value*> vv( myhist->getVectorOfValues() ); + std::vector<double> val( getNumberOfArguments() ), der( getNumberOfArguments() ); + // Retrieve the location of the grid point at which we are evaluating the kernel + mygrid->getGridPointCoordinates( current, val ); + if( kernel ) { + for(unsigned i=0; i<getNumberOfArguments(); ++i) vv[i]->set( val[i] ); + // Evaluate the histogram at the relevant grid point and set the values + double vvh = kernel->evaluate( vv, der,true); myvals.setValue( 1, vvh ); + } else { + plumed_merror("normalisation of vectors does not work with arguments and spherical grids"); + // Evalulate dot product + double dot=0; for(unsigned j=0; j<getNumberOfArguments(); ++j) { dot+=val[j]*getArgument(j); der[j]=val[j]; } + // Von misses distribution for concentration parameter + double newval = (myhist->von_misses_norm)*exp( (myhist->von_misses_concentration)*dot ); myvals.setValue( 1, newval ); + // And final derivatives + for(unsigned j=0; j<getNumberOfArguments(); ++j) der[j] *= (myhist->von_misses_concentration)*newval; + } + // Set the derivatives and delete the vector of values + for(unsigned i=0; i<getNumberOfArguments(); ++i) { myvals.setDerivative( 1, i, der[i] ); delete vv[i]; } } } -void Histogram::apply(){ +void Histogram::apply() { if( !myhist->wasForced() ) return ; - in_apply=true; + in_apply=true; // Run the loop to calculate the forces - runAllTasks(); finishAveraging(); + runAllTasks(); finishAveraging(); // We now need to retrieve the buffer and set the forces on the atoms - myhist->applyForce( forcesToApply ); + myhist->applyForce( forcesToApply ); // Now make the forces make sense for the virial unsigned fbase=0, tbase=0, vbase = getNumberOfDerivatives() - myvessels.size()*9; - for(unsigned i=vbase;i<vbase+9;++i) finalForces[i]=0.0; - for(unsigned i=0;i<myvessels.size();++i){ - for(unsigned j=0;j<myvessels[i]->getNumberOfDerivatives()-9;++j){ - finalForces[fbase + j] = forcesToApply[tbase + j]; - } - unsigned k=0; - for(unsigned j=myvessels[i]->getNumberOfDerivatives()-9;j<myvessels[i]->getNumberOfDerivatives();++j){ - finalForces[vbase + k] += forcesToApply[tbase + j]; k++; - } - fbase += myvessels[i]->getNumberOfDerivatives() - 9; - tbase += myvessels[i]->getNumberOfDerivatives(); + for(unsigned i=vbase; i<vbase+9; ++i) finalForces[i]=0.0; + for(unsigned i=0; i<myvessels.size(); ++i) { + for(unsigned j=0; j<myvessels[i]->getNumberOfDerivatives()-9; ++j) { + finalForces[fbase + j] = forcesToApply[tbase + j]; + } + unsigned k=0; + for(unsigned j=myvessels[i]->getNumberOfDerivatives()-9; j<myvessels[i]->getNumberOfDerivatives(); ++j) { + finalForces[vbase + k] += forcesToApply[tbase + j]; k++; + } + fbase += myvessels[i]->getNumberOfDerivatives() - 9; + tbase += myvessels[i]->getNumberOfDerivatives(); } // And set the final forces on the atoms setForcesOnAtoms( finalForces ); // Reset everything for next regular loop - in_apply=false; + in_apply=false; } } diff --git a/src/analysis/LandmarkRegister.cpp b/src/analysis/LandmarkRegister.cpp index 32cc946d5..0b3a6e4f7 100644 --- a/src/analysis/LandmarkRegister.cpp +++ b/src/analysis/LandmarkRegister.cpp @@ -22,45 +22,45 @@ #include "LandmarkRegister.h" #include <iostream> -namespace PLMD{ -namespace analysis{ +namespace PLMD { +namespace analysis { -LandmarkRegister::~LandmarkRegister(){ - if(m.size()>0){ +LandmarkRegister::~LandmarkRegister() { + if(m.size()>0) { std::string names=""; for(const auto & p : m) names+=p.first+" "; std::cerr<<"WARNING: ReferenceConfiguration "+ names +" has not been properly unregistered. This might lead to memory leak!!\n"; } } -LandmarkRegister& landmarkRegister(){ +LandmarkRegister& landmarkRegister() { static LandmarkRegister ans; return ans; } -void LandmarkRegister::remove(creator_pointer f){ - for(auto p=m.begin();p!=m.end();++p){ - if((*p).second==f){ +void LandmarkRegister::remove(creator_pointer f) { + for(auto p=m.begin(); p!=m.end(); ++p) { + if((*p).second==f) { m.erase(p); break; } } } -void LandmarkRegister::add( std::string type, creator_pointer f ){ +void LandmarkRegister::add( std::string type, creator_pointer f ) { plumed_massert(m.count(type)==0,"type has already been registered"); m.insert(std::pair<std::string,creator_pointer>(type,f)); } -bool LandmarkRegister::check(std::string type){ +bool LandmarkRegister::check(std::string type) { if( m.count(type)>0 ) return true; return false; } -LandmarkSelectionBase* LandmarkRegister::create( const LandmarkSelectionOptions& lo ){ +LandmarkSelectionBase* LandmarkRegister::create( const LandmarkSelectionOptions& lo ) { LandmarkSelectionBase* lselect; - if( check(lo.words[0]) ){ - lselect=m[lo.words[0]](lo); - lselect->checkRead(); + if( check(lo.words[0]) ) { + lselect=m[lo.words[0]](lo); + lselect->checkRead(); } else lselect=NULL; return lselect; } diff --git a/src/analysis/LandmarkRegister.h b/src/analysis/LandmarkRegister.h index e17c9b2ab..dd4c5d38d 100644 --- a/src/analysis/LandmarkRegister.h +++ b/src/analysis/LandmarkRegister.h @@ -28,13 +28,13 @@ #include <map> #include "LandmarkSelectionBase.h" -namespace PLMD{ +namespace PLMD { class PDB; -namespace analysis{ +namespace analysis { -class LandmarkRegister{ +class LandmarkRegister { private: /// Pointer to a function which, given the type for a ReferenceConfiguration, creates it typedef LandmarkSelectionBase*(*creator_pointer)(const LandmarkSelectionOptions&); diff --git a/src/analysis/LandmarkSelectionBase.cpp b/src/analysis/LandmarkSelectionBase.cpp index 24df3c1d1..5bd8f7e60 100644 --- a/src/analysis/LandmarkSelectionBase.cpp +++ b/src/analysis/LandmarkSelectionBase.cpp @@ -26,88 +26,88 @@ namespace PLMD { namespace analysis { LandmarkSelectionOptions::LandmarkSelectionOptions( const std::vector<std::string>& input, AnalysisWithLandmarks* myanalysis ): -words(input), -action(myanalysis) + words(input), + action(myanalysis) { } LandmarkSelectionBase::LandmarkSelectionBase( const LandmarkSelectionOptions& lo ): -style(lo.words[0]), -input(lo.words), -action(lo.action) + style(lo.words[0]), + input(lo.words), + action(lo.action) { input.erase( input.begin() ); - if( style=="ALL" ){ - novoronoi=true; + if( style=="ALL" ) { + novoronoi=true; } else { - parse("N",nlandmarks); - parseFlag("NOVORONOI",novoronoi); + parse("N",nlandmarks); + parseFlag("NOVORONOI",novoronoi); } parseFlag("IGNORE_WEIGHTS",noweights); } -LandmarkSelectionBase::~LandmarkSelectionBase(){ +LandmarkSelectionBase::~LandmarkSelectionBase() { } -void LandmarkSelectionBase::parseFlag(const std::string& key, bool& t){ +void LandmarkSelectionBase::parseFlag(const std::string& key, bool& t) { Tools::parseFlag(input,key,t); } void LandmarkSelectionBase::checkRead() const { - if(!input.empty()){ - std::string msg="cannot understand the following words from landmark selection input : "; - for(unsigned i=0;i<input.size();++i) msg = msg + input[i] + ", "; - plumed_merror(msg); + if(!input.empty()) { + std::string msg="cannot understand the following words from landmark selection input : "; + for(unsigned i=0; i<input.size(); ++i) msg = msg + input[i] + ", "; + plumed_merror(msg); } } -std::string LandmarkSelectionBase::description(){ +std::string LandmarkSelectionBase::description() { std::ostringstream ostr; - if( style=="ALL"){ - ostr<<"using all data"; + if( style=="ALL") { + ostr<<"using all data"; } else { - ostr<<"selecting "<<nlandmarks<<" using "<<style<<" algorithm to analyze\n"; - ostr<<" "<<rest_of_description()<<"\n"; - if(noweights) ostr<<" ignoring all reweighting of data during landmark selection\n"; - if(novoronoi) ostr<<" voronoi weights will not be ascribed to points\n"; + ostr<<"selecting "<<nlandmarks<<" using "<<style<<" algorithm to analyze\n"; + ostr<<" "<<rest_of_description()<<"\n"; + if(noweights) ostr<<" ignoring all reweighting of data during landmark selection\n"; + if(novoronoi) ostr<<" voronoi weights will not be ascribed to points\n"; } return ostr.str(); } -double LandmarkSelectionBase::getWeightOfFrame( const unsigned& iframe ){ +double LandmarkSelectionBase::getWeightOfFrame( const unsigned& iframe ) { if(noweights) return 1.0; return action->getWeight(iframe); } -double LandmarkSelectionBase::getDistanceBetweenFrames( const unsigned& iframe, const unsigned& jframe ){ +double LandmarkSelectionBase::getDistanceBetweenFrames( const unsigned& iframe, const unsigned& jframe ) { return distance( action->getPbc(), action->getArguments(), action->data[iframe], action->data[jframe], false ); } -void LandmarkSelectionBase::selectFrame( const unsigned& iframe, MultiReferenceBase* myframes){ +void LandmarkSelectionBase::selectFrame( const unsigned& iframe, MultiReferenceBase* myframes) { plumed_assert( myframes->getNumberOfReferenceFrames()<nlandmarks ); myframes->copyFrame( action->data[iframe] ); } -void LandmarkSelectionBase::selectLandmarks( MultiReferenceBase* myframes ){ +void LandmarkSelectionBase::selectLandmarks( MultiReferenceBase* myframes ) { // Select landmarks myframes->clearFrames(); select( myframes ); plumed_assert( myframes->getNumberOfReferenceFrames()==nlandmarks ); - // Now calculate voronoi weights - if( !novoronoi ){ - unsigned rank=action->comm.Get_rank(); - unsigned size=action->comm.Get_size(); - std::vector<double> weights( nlandmarks, 0.0 ); - for(unsigned i=rank;i<action->data.size();i+=size){ - unsigned closest=0; - double mindist=distance( action->getPbc(), action->getArguments(), action->data[i], myframes->getFrame(0), false ); - for(unsigned j=1;j<nlandmarks;++j){ - double dist=distance( action->getPbc(), action->getArguments(), action->data[i], myframes->getFrame(j), false ); - if( dist<mindist ){ mindist=dist; closest=j; } - } - weights[closest] += getWeightOfFrame(i); + // Now calculate voronoi weights + if( !novoronoi ) { + unsigned rank=action->comm.Get_rank(); + unsigned size=action->comm.Get_size(); + std::vector<double> weights( nlandmarks, 0.0 ); + for(unsigned i=rank; i<action->data.size(); i+=size) { + unsigned closest=0; + double mindist=distance( action->getPbc(), action->getArguments(), action->data[i], myframes->getFrame(0), false ); + for(unsigned j=1; j<nlandmarks; ++j) { + double dist=distance( action->getPbc(), action->getArguments(), action->data[i], myframes->getFrame(j), false ); + if( dist<mindist ) { mindist=dist; closest=j; } } - action->comm.Sum( &weights[0], weights.size() ); - myframes->setWeights( weights ); + weights[closest] += getWeightOfFrame(i); + } + action->comm.Sum( &weights[0], weights.size() ); + myframes->setWeights( weights ); } } diff --git a/src/analysis/LandmarkSelectionBase.h b/src/analysis/LandmarkSelectionBase.h index b2deb5c57..a8300ff10 100644 --- a/src/analysis/LandmarkSelectionBase.h +++ b/src/analysis/LandmarkSelectionBase.h @@ -28,9 +28,9 @@ namespace PLMD { namespace analysis { -class LandmarkSelectionOptions{ -friend class LandmarkRegister; -friend class LandmarkSelectionBase; +class LandmarkSelectionOptions { + friend class LandmarkRegister; + friend class LandmarkSelectionBase; private: std::vector<std::string> words; AnalysisWithLandmarks* action; @@ -39,8 +39,8 @@ public: }; class LandmarkSelectionBase { -friend class AnalysisWithLandmarks; -friend class CopyAllFrames; + friend class AnalysisWithLandmarks; + friend class CopyAllFrames; private: /// Name of the method we are using for landmark selection std::string style; @@ -57,9 +57,9 @@ protected: unsigned getNumberOfLandmarks() const ; /// Return the communicator Communicator& getCommunicator(); -/// Read a keywords from the input +/// Read a keywords from the input template <class T> - void parse(const std::string& ,T& ); + void parse(const std::string&,T& ); /// Read a flag from the input void parseFlag(const std::string& key, bool& t); /// Get the number of frames in the underlying action @@ -67,9 +67,9 @@ protected: /// Get the weight of the ith frame double getWeightOfFrame( const unsigned& ); /// Calculate the distance between the ith and jth frames - double getDistanceBetweenFrames( const unsigned& , const unsigned& ); + double getDistanceBetweenFrames( const unsigned&, const unsigned& ); /// Transfer frame i in the underlying action to the object we are going to analyze - void selectFrame( const unsigned& , MultiReferenceBase* ); + void selectFrame( const unsigned&, MultiReferenceBase* ); public: explicit LandmarkSelectionBase( const LandmarkSelectionOptions& lo ); virtual ~LandmarkSelectionBase(); @@ -78,7 +78,7 @@ public: /// Return a description of the landmark selection protocol std::string description(); /// Overwrite this to have a more descriptive output - virtual std::string rest_of_description(){ return ""; }; + virtual std::string rest_of_description() { return ""; }; /// Actually do landmark selection void selectLandmarks( MultiReferenceBase* ); virtual void select( MultiReferenceBase* )=0; @@ -90,7 +90,7 @@ unsigned LandmarkSelectionBase::getNumberOfLandmarks() const { } inline -Communicator& LandmarkSelectionBase::getCommunicator(){ +Communicator& LandmarkSelectionBase::getCommunicator() { return action->comm; } @@ -100,7 +100,7 @@ unsigned LandmarkSelectionBase::getNumberOfFrames() const { } template <class T> -void LandmarkSelectionBase::parse( const std::string& key, T& t ){ +void LandmarkSelectionBase::parse( const std::string& key, T& t ) { bool found=Tools::parse(input,key,t); if(!found) plumed_merror("landmark seleciton style " + style + " requires " + key + " keyword"); } diff --git a/src/analysis/PCA.cpp b/src/analysis/PCA.cpp index d338b5b8a..5b31a04fa 100644 --- a/src/analysis/PCA.cpp +++ b/src/analysis/PCA.cpp @@ -28,32 +28,32 @@ #include "core/ActionRegister.h" //+PLUMEDOC DIMRED PCA -/* +/* Perform principal component analysis (PCA) using either the positions of the atoms a large number of collective variables as input. -Principal component analysis is a statistical technique that uses an orthogonal transformation to convert a set of observations of +Principal component analysis is a statistical technique that uses an orthogonal transformation to convert a set of observations of poorly correlated variables into a set of linearly uncorrelated variables. You can read more about the specifics of this technique here: https://en.wikipedia.org/wiki/Principal_component_analysis -When used with molecular dynamics simulations a set of frames taken from the trajectory, \f$\{X_i\}\f$, or the values of -a number of collective variables which are calculated from the trajectory frames are used as input. In this second instance your +When used with molecular dynamics simulations a set of frames taken from the trajectory, \f$\{X_i\}\f$, or the values of +a number of collective variables which are calculated from the trajectory frames are used as input. In this second instance your input to the PCA analysis algorithm is thus a set of high-dimensional vectors of collective variables. However, if -collective variables are calculated from the positions of the atoms or if the positions are used directly the assumption is that -this input trajectory is a set of poorly correlated (high-dimensional) vectors. After principal component analysis has been -performed the output is a set of orthogonal vectors that describe the directions in which the largest motions have been seen. +collective variables are calculated from the positions of the atoms or if the positions are used directly the assumption is that +this input trajectory is a set of poorly correlated (high-dimensional) vectors. After principal component analysis has been +performed the output is a set of orthogonal vectors that describe the directions in which the largest motions have been seen. In other words, principal component analysis provides a method for lowering the dimensionality of the data contained in a trajectory. -These output directions are some linear combination of the \f$x\f$, \f$y\f$ and \f$z\f$ positions if the positions were used as input +These output directions are some linear combination of the \f$x\f$, \f$y\f$ and \f$z\f$ positions if the positions were used as input or some linear combination of the input collective variables if a high-dimensional vector of collective variables was used as input. -As explained on the Wikipedia page you must calculate the average and covariance for each of the input coordinates. In other words, you must -calculate the average structure and the amount the system fluctuates around this average structure. The problem in doing so when the -\f$x\f$, \f$y\f$ and \f$z\f$ coordinates of a molecule are used as input is that the majority of the changes in the positions of the +As explained on the Wikipedia page you must calculate the average and covariance for each of the input coordinates. In other words, you must +calculate the average structure and the amount the system fluctuates around this average structure. The problem in doing so when the +\f$x\f$, \f$y\f$ and \f$z\f$ coordinates of a molecule are used as input is that the majority of the changes in the positions of the atoms comes from the translational and rotational degrees of freedom of the molecule. The first six principal components will thus, most likely, -be uninteresting. Consequently, to remedy this problem PLUMED provides the functionality to perform an RMSD alignment of the all the structures -to be analysed to the first frame in the trajectory. This can be used to effectively remove translational and/or rotational motions from -consideration. The resulting principal components thus describe vibrational motions of the molecule. +be uninteresting. Consequently, to remedy this problem PLUMED provides the functionality to perform an RMSD alignment of the all the structures +to be analysed to the first frame in the trajectory. This can be used to effectively remove translational and/or rotational motions from +consideration. The resulting principal components thus describe vibrational motions of the molecule. -If you wish to calculate the projection of a trajectory on a set of principal components calculated from this PCA action then the output can be +If you wish to calculate the projection of a trajectory on a set of principal components calculated from this PCA action then the output can be used as input for the \ref PCAVARS action. \par Examples @@ -70,10 +70,10 @@ PCA METRIC=OPTIMAL ATOMS=1-22 STRIDE=1 USE_ALL_DATA NLOW_DIM=2 OFILE=pca-comp.pd The following input instructs PLUMED to perform a principal component analysis in which the covariance matrix is calculated from chnages in the six distances seen in the previous lines. Notice that here the TYPE=EUCLIDEAN keyword is used to indicate that no alighment has to be done when calculating the various elements of the covariance matrix from the input vectors. In this calculation the first two principal components will be output to a file called pca-comp.pdb. -Trajectory frames will be collected every five steps and the PCA calculation is performed every 1000 steps. Consequently, if you run a 2000 step simulation the +Trajectory frames will be collected every five steps and the PCA calculation is performed every 1000 steps. Consequently, if you run a 2000 step simulation the PCA analysis will be performed twice. The REWEIGHT_BIAS keyword in this input tells PLUMED that rather that ascribing a weight of one to each of the frames -when calculating averages and covariances a reweighting should be performed based and each frames' weight in these calculations should be determined based on -the current value of the instantaneous bias (see \ref REWEIGHT_BIAS). +when calculating averages and covariances a reweighting should be performed based and each frames' weight in these calculations should be determined based on +the current value of the instantaneous bias (see \ref REWEIGHT_BIAS). \verbatim d1: DISTANCE ATOMS=1,2 @@ -107,27 +107,27 @@ public: explicit PCA(const ActionOptions&ao); ~PCA(); void performAnalysis(); - void performTask( const unsigned& , const unsigned& , MultiValue& ) const { plumed_error(); } + void performTask( const unsigned&, const unsigned&, MultiValue& ) const { plumed_error(); } }; PLUMED_REGISTER_ACTION(PCA,"PCA") -void PCA::registerKeywords( Keywords& keys ){ +void PCA::registerKeywords( Keywords& keys ) { Analysis::registerKeywords( keys ); keys.add("compulsory","NLOW_DIM","number of PCA coordinates required"); keys.add("compulsory","OFILE","the file on which to output the eigenvectors"); } PCA::PCA(const ActionOptions&ao): -PLUMED_ANALYSIS_INIT(ao) + PLUMED_ANALYSIS_INIT(ao) { // Setup reference configuration log.printf(" performing PCA analysis using %s metric \n", getMetricName().c_str() ); myref = metricRegister().create<ReferenceConfiguration>( getMetricName() ); std::vector<std::string> argnames( getNumberOfArguments() ); - for(unsigned i=0;i<argnames.size();++i){ - if( getArguments()[i]->isPeriodic() ) error("cannot run PCA with periodic variables"); - argnames[i] = getArguments()[i]->getName(); + for(unsigned i=0; i<argnames.size(); ++i) { + if( getArguments()[i]->isPeriodic() ) error("cannot run PCA with periodic variables"); + argnames[i] = getArguments()[i]->getName(); } myref->setNamesAndAtomNumbers( getAbsoluteIndexes(), argnames ); @@ -136,74 +136,74 @@ PLUMED_ANALYSIS_INIT(ao) if( getNumberOfArguments()>0 ) arg_eigv.resize( ndim, getNumberOfArguments() ); // Read stuff for output file - parseOutputFile("OFILE",ofilename); + parseOutputFile("OFILE",ofilename); checkRead(); } -PCA::~PCA(){ +PCA::~PCA() { delete myref; } -void PCA::performAnalysis(){ +void PCA::performAnalysis() { // Align everything to the first frame MultiValue myval( 1, getNumberOfArguments() + 3*getNumberOfAtoms() + 9 ); ReferenceValuePack mypack( getNumberOfArguments(), getNumberOfAtoms(), myval ); - for(unsigned i=0;i<getNumberOfAtoms();++i) mypack.setAtomIndex( i, i ); - // Setup some PCA storage + for(unsigned i=0; i<getNumberOfAtoms(); ++i) mypack.setAtomIndex( i, i ); + // Setup some PCA storage data[0]->setupPCAStorage ( mypack ); // Create some arrays to store the average position std::vector<double> sarg( getNumberOfArguments(), 0 ); std::vector<Vector> spos( getNumberOfAtoms() ); - for(unsigned i=0;i<getNumberOfAtoms();++i) spos[i].zero(); - + for(unsigned i=0; i<getNumberOfAtoms(); ++i) spos[i].zero(); + // Calculate the average displacement from the first frame - double norm=getWeight(0); - for(unsigned i=1;i<getNumberOfDataPoints();++i){ - double d = data[0]->calc( data[i]->getReferencePositions(), getPbc(), getArguments(), data[i]->getReferenceArguments(), mypack, true ); - // Accumulate average displacement of arguments (Here PBC could do fucked up things - really needs Berry Phase ) GAT - for(unsigned j=0;j<getNumberOfArguments();++j) sarg[j] += 0.5*getWeight(i)*mypack.getArgumentDerivative(j); - // Accumulate average displacement of position - for(unsigned j=0;j<getNumberOfAtoms();++j) spos[j] += getWeight(i)*mypack.getAtomsDisplacementVector()[j]; - norm += getWeight(i); + double norm=getWeight(0); + for(unsigned i=1; i<getNumberOfDataPoints(); ++i) { + double d = data[0]->calc( data[i]->getReferencePositions(), getPbc(), getArguments(), data[i]->getReferenceArguments(), mypack, true ); + // Accumulate average displacement of arguments (Here PBC could do fucked up things - really needs Berry Phase ) GAT + for(unsigned j=0; j<getNumberOfArguments(); ++j) sarg[j] += 0.5*getWeight(i)*mypack.getArgumentDerivative(j); + // Accumulate average displacement of position + for(unsigned j=0; j<getNumberOfAtoms(); ++j) spos[j] += getWeight(i)*mypack.getAtomsDisplacementVector()[j]; + norm += getWeight(i); } // Now normalise the displacements to get the average and add these to the first frame - double inorm = 1.0 / norm ; - for(unsigned j=0;j<getNumberOfArguments();++j) sarg[j] = inorm*sarg[j] + data[0]->getReferenceArguments()[j]; - for(unsigned j=0;j<getNumberOfAtoms();++j) spos[j] = inorm*spos[j] + data[0]->getReferencePositions()[j]; + double inorm = 1.0 / norm ; + for(unsigned j=0; j<getNumberOfArguments(); ++j) sarg[j] = inorm*sarg[j] + data[0]->getReferenceArguments()[j]; + for(unsigned j=0; j<getNumberOfAtoms(); ++j) spos[j] = inorm*spos[j] + data[0]->getReferencePositions()[j]; // And set the reference configuration - std::vector<double> empty( getNumberOfArguments(), 1.0 ); myref->setReferenceConfig( spos, sarg, empty ); + std::vector<double> empty( getNumberOfArguments(), 1.0 ); myref->setReferenceConfig( spos, sarg, empty ); // Now accumulate the covariance unsigned narg=getNumberOfArguments(); Matrix<double> covar( getNumberOfArguments()+3*getNumberOfAtoms(), getNumberOfArguments()+3*getNumberOfAtoms() ); covar=0; - for(unsigned i=0;i<getNumberOfDataPoints();++i){ - // double d = data[i]->calc( spos, getPbc(), getArguments(), sarg, mypack, true ); - double d = data[0]->calc( data[i]->getReferencePositions(), getPbc(), getArguments(), data[i]->getReferenceArguments(), mypack, true ); - for(unsigned jarg=0;jarg<getNumberOfArguments();++jarg){ - // Need sorting for PBC with GAT - double jarg_d = 0.5*mypack.getArgumentDerivative(jarg) + data[0]->getReferenceArguments()[jarg] - sarg[jarg]; - for(unsigned karg=0;karg<getNumberOfArguments();++karg){ - // Need sorting for PBC with GAT - double karg_d = 0.5*mypack.getArgumentDerivative(karg) + data[0]->getReferenceArguments()[karg] - sarg[karg]; - covar( jarg, karg ) += 0.25*getWeight(i)*jarg_d*karg_d; // mypack.getArgumentDerivative(jarg)*mypack.getArgumentDerivative(karg); - } + for(unsigned i=0; i<getNumberOfDataPoints(); ++i) { + // double d = data[i]->calc( spos, getPbc(), getArguments(), sarg, mypack, true ); + double d = data[0]->calc( data[i]->getReferencePositions(), getPbc(), getArguments(), data[i]->getReferenceArguments(), mypack, true ); + for(unsigned jarg=0; jarg<getNumberOfArguments(); ++jarg) { + // Need sorting for PBC with GAT + double jarg_d = 0.5*mypack.getArgumentDerivative(jarg) + data[0]->getReferenceArguments()[jarg] - sarg[jarg]; + for(unsigned karg=0; karg<getNumberOfArguments(); ++karg) { + // Need sorting for PBC with GAT + double karg_d = 0.5*mypack.getArgumentDerivative(karg) + data[0]->getReferenceArguments()[karg] - sarg[karg]; + covar( jarg, karg ) += 0.25*getWeight(i)*jarg_d*karg_d; // mypack.getArgumentDerivative(jarg)*mypack.getArgumentDerivative(karg); } - for(unsigned jat=0;jat<getNumberOfAtoms();++jat){ - for(unsigned jc=0;jc<3;++jc){ - double jdisplace = mypack.getAtomsDisplacementVector()[jat][jc] + data[0]->getReferencePositions()[jat][jc] - spos[jat][jc]; - for(unsigned kat=0;kat<getNumberOfAtoms();++kat){ - for(unsigned kc=0;kc<3;++kc){ - double kdisplace = mypack.getAtomsDisplacementVector()[kat][kc] + data[0]->getReferencePositions()[kat][kc] - spos[kat][kc]; - covar( narg+3*jat + jc, narg+3*kat + kc ) += getWeight(i)*jdisplace*kdisplace; - } - } - } + } + for(unsigned jat=0; jat<getNumberOfAtoms(); ++jat) { + for(unsigned jc=0; jc<3; ++jc) { + double jdisplace = mypack.getAtomsDisplacementVector()[jat][jc] + data[0]->getReferencePositions()[jat][jc] - spos[jat][jc]; + for(unsigned kat=0; kat<getNumberOfAtoms(); ++kat) { + for(unsigned kc=0; kc<3; ++kc) { + double kdisplace = mypack.getAtomsDisplacementVector()[kat][kc] + data[0]->getReferencePositions()[kat][kc] - spos[kat][kc]; + covar( narg+3*jat + jc, narg+3*kat + kc ) += getWeight(i)*jdisplace*kdisplace; + } + } } + } } // Normalise - for(unsigned i=0;i<covar.nrows();++i){ - for(unsigned j=0;j<covar.ncols();++j) covar(i,j) *= inorm; + for(unsigned i=0; i<covar.nrows(); ++i) { + for(unsigned j=0; j<covar.ncols(); ++j) covar(i,j) *= inorm; } // Diagonalise the covariance @@ -213,25 +213,25 @@ void PCA::performAnalysis(){ // Open an output file OFile ofile; ofile.link(*this); ofile.setBackupString("analysis"); - ofile.open( ofilename ); + ofile.open( ofilename ); // Output the reference configuration - myref->print( ofile, getOutputFormat(), atoms.getUnits().getLength()/0.1 ); + myref->print( ofile, getOutputFormat(), atoms.getUnits().getLength()/0.1 ); // Store and print the eigenvectors std::vector<Vector> tmp_atoms( getNumberOfAtoms() ); std::vector<double> tmp_args( getNumberOfArguments() ); Direction* tref = metricRegister().create<Direction>( "DIRECTION" ); tref->setNamesAndAtomNumbers( getAbsoluteIndexes(), argument_names ); - for(unsigned dim=0;dim<ndim;++dim){ - unsigned idim = covar.ncols() - 1 - dim; - for(unsigned i=0;i<getNumberOfArguments();++i) tmp_args[i]=arg_eigv(dim,i)=eigvec(idim,i); - for(unsigned i=0;i<getNumberOfAtoms();++i){ - for(unsigned k=0;k<3;++k) tmp_atoms[i][k]=atom_eigv(dim,i)[k]=eigvec(idim,narg+3*i+k); - } - tref->setDirection( tmp_atoms, tmp_args ); - tref->print( ofile, getOutputFormat(), atoms.getUnits().getLength()/0.1 ); - } - // Close the output file + for(unsigned dim=0; dim<ndim; ++dim) { + unsigned idim = covar.ncols() - 1 - dim; + for(unsigned i=0; i<getNumberOfArguments(); ++i) tmp_args[i]=arg_eigv(dim,i)=eigvec(idim,i); + for(unsigned i=0; i<getNumberOfAtoms(); ++i) { + for(unsigned k=0; k<3; ++k) tmp_atoms[i][k]=atom_eigv(dim,i)[k]=eigvec(idim,narg+3*i+k); + } + tref->setDirection( tmp_atoms, tmp_args ); + tref->print( ofile, getOutputFormat(), atoms.getUnits().getLength()/0.1 ); + } + // Close the output file delete tref; ofile.close(); } diff --git a/src/analysis/SelectAllFrames.cpp b/src/analysis/SelectAllFrames.cpp index 56ea3751f..8f61b7305 100644 --- a/src/analysis/SelectAllFrames.cpp +++ b/src/analysis/SelectAllFrames.cpp @@ -34,13 +34,13 @@ public: PLUMED_REGISTER_LANDMARKS(CopyAllFrames,"ALL") CopyAllFrames::CopyAllFrames( const LandmarkSelectionOptions& lo ): -LandmarkSelectionBase(lo) + LandmarkSelectionBase(lo) { } -void CopyAllFrames::select( MultiReferenceBase* myframes ){ +void CopyAllFrames::select( MultiReferenceBase* myframes ) { nlandmarks = action->getNumberOfDataPoints(); - for(unsigned i=0;i<getNumberOfFrames();++i) selectFrame( i, myframes ); + for(unsigned i=0; i<getNumberOfFrames(); ++i) selectFrame( i, myframes ); } } diff --git a/src/bias/ABMD.cpp b/src/bias/ABMD.cpp index 2992af453..5e8bef344 100644 --- a/src/bias/ABMD.cpp +++ b/src/bias/ABMD.cpp @@ -26,16 +26,16 @@ using namespace std; -namespace PLMD{ -namespace bias{ +namespace PLMD { +namespace bias { -//+PLUMEDOC BIAS ABMD +//+PLUMEDOC BIAS ABMD /* Adds a ratchet-and-pawl like restraint on one or more variables. This action can be used to evolve a system towards a target value in CV space using an harmonic potential moving with the thermal fluctuations of the CV -\cite ballone \cite provasi10abmd \cite camilloni11abmd. The biasing potential in this +\cite ballone \cite provasi10abmd \cite camilloni11abmd. The biasing potential in this method is as follows: \f$ @@ -64,7 +64,7 @@ the system is moving towards the desired arrival point and which damps the fluctuations when the system attempts to move in the opposite direction. As in the case of the ratchet and pawl system, propelled by thermal motion of the solvent molecules, the biasing potential does not exert work on the system. \f$\eta(t)\f$ is -an additional white noise acting on the minimum position of the bias. +an additional white noise acting on the minimum position of the bias. \par Examples The following input sets up two biases, one on the distance between atoms 3 and 5 @@ -81,7 +81,7 @@ PRINT ARG=abmd.bias,abmd.d1_min,abmd.d2_min */ //+ENDPLUMEDOC -class ABMD : public Bias{ +class ABMD : public Bias { std::vector<double> to; std::vector<double> min; std::vector<double> kappa; @@ -96,7 +96,7 @@ public: PLUMED_REGISTER_ACTION(ABMD,"ABMD") -void ABMD::registerKeywords(Keywords& keys){ +void ABMD::registerKeywords(Keywords& keys) { Bias::registerKeywords(keys); keys.use("ARG"); keys.add("compulsory","TO","The array of target values"); @@ -106,18 +106,18 @@ void ABMD::registerKeywords(Keywords& keys){ keys.add("optional","SEED","Array of seeds for the white noise (add a temperature to the ABMD)"); keys.addOutputComponent("force2","default","the instantaneous value of the squared force due to this bias potential"); keys.addOutputComponent("_min","default","one or multiple instances of this quantity will be refereceable elsewhere in the input file. " - " These quantities will be named with the arguments of the bias followed by " - "the character string _min. These quantities tell the user the minimum value assumed by rho_m(t)."); + " These quantities will be named with the arguments of the bias followed by " + "the character string _min. These quantities tell the user the minimum value assumed by rho_m(t)."); } ABMD::ABMD(const ActionOptions&ao): -PLUMED_BIAS_INIT(ao), -to(getNumberOfArguments(),0.0), -min(getNumberOfArguments(),-1.0), -kappa(getNumberOfArguments(),0.0), -temp(getNumberOfArguments(),0.0), -seed(getNumberOfArguments(),time(0)), -random(getNumberOfArguments()) + PLUMED_BIAS_INIT(ao), + to(getNumberOfArguments(),0.0), + min(getNumberOfArguments(),-1.0), + kappa(getNumberOfArguments(),0.0), + temp(getNumberOfArguments(),0.0), + seed(getNumberOfArguments(),time(0)), + random(getNumberOfArguments()) { // Note : parseVector will check that number of arguments is correct parseVector("KAPPA",kappa); @@ -130,35 +130,35 @@ random(getNumberOfArguments()) checkRead(); log.printf(" min"); - for(unsigned i=0;i<min.size();i++) log.printf(" %f",min[i]); + for(unsigned i=0; i<min.size(); i++) log.printf(" %f",min[i]); log.printf("\n"); log.printf(" to"); - for(unsigned i=0;i<to.size();i++) log.printf(" %f",to[i]); + for(unsigned i=0; i<to.size(); i++) log.printf(" %f",to[i]); log.printf("\n"); log.printf(" with force constant"); - for(unsigned i=0;i<kappa.size();i++) log.printf(" %f",kappa[i]); + for(unsigned i=0; i<kappa.size(); i++) log.printf(" %f",kappa[i]); log.printf("\n"); - for(unsigned i=0;i<getNumberOfArguments();i++) { - std::string str_min=getPntrToArgument(i)->getName()+"_min"; - addComponent(str_min); componentIsNotPeriodic(str_min); - if(min[i]!=-1.0) getPntrToComponent(str_min)->set(min[i]); + for(unsigned i=0; i<getNumberOfArguments(); i++) { + std::string str_min=getPntrToArgument(i)->getName()+"_min"; + addComponent(str_min); componentIsNotPeriodic(str_min); + if(min[i]!=-1.0) getPntrToComponent(str_min)->set(min[i]); } - for(unsigned i=0;i<getNumberOfArguments();i++) {random[i].setSeed(-seed[i]);} + for(unsigned i=0; i<getNumberOfArguments(); i++) {random[i].setSeed(-seed[i]);} addComponent("force2"); componentIsNotPeriodic("force2"); } -void ABMD::calculate(){ +void ABMD::calculate() { double ene=0.0; double totf2=0.0; - for(unsigned i=0;i<getNumberOfArguments();++i){ + for(unsigned i=0; i<getNumberOfArguments(); ++i) { const double cv=difference(i,to[i],getArgument(i)); const double cv2=cv*cv; const double k=kappa[i]; double noise=0.; double diff=temp[i]; - if(diff>0) { + if(diff>0) { noise = 2.*random[i].Gaussian()*diff; if(cv2<=diff) { diff=0.; temp[i]=0.; } } @@ -166,11 +166,11 @@ void ABMD::calculate(){ // min < 0 means that the variable has not been used in the input file, so the current position of the CV is used // cv2 < min means that the collective variable is nearer to the target value than at any other previous time so // min is set to the CV value - if(min[i]<0.||cv2<min[i]) { - min[i] = cv2; + if(min[i]<0.||cv2<min[i]) { + min[i] = cv2; } else { // otherwise a noise is added to the minimum value - min[i] += noise; + min[i] += noise; const double f = -2.*k*(cv2-min[i])*cv; setOutputForce(i,f); ene += 0.5*k*(cv2-min[i])*(cv2-min[i]); diff --git a/src/bias/Bias.cpp b/src/bias/Bias.cpp index 312dbc81d..4075e3433 100644 --- a/src/bias/Bias.cpp +++ b/src/bias/Bias.cpp @@ -22,32 +22,32 @@ #include "Bias.h" -namespace PLMD{ -namespace bias{ +namespace PLMD { +namespace bias { Bias::Bias(const ActionOptions&ao): -Action(ao), -ActionPilot(ao), -ActionWithValue(ao), -ActionWithArguments(ao), -outputForces(getNumberOfArguments(),0.0) + Action(ao), + ActionPilot(ao), + ActionWithValue(ao), + ActionWithArguments(ao), + outputForces(getNumberOfArguments(),0.0) { - addComponentWithDerivatives("bias"); + addComponentWithDerivatives("bias"); componentIsNotPeriodic("bias"); valueBias=getPntrToComponent("bias"); - if(getStride()>1){ + if(getStride()>1) { log<<" multiple time step "<<getStride()<<" "; log<<cite("Ferrarotti, Bottaro, Perez-Villa, and Bussi, J. Chem. Theory Comput. 11, 139 (2015)")<<"\n"; } - for(unsigned i=0;i<getNumberOfArguments();++i){ - (getPntrToArgument(i)->getPntrToAction())->turnOnDerivatives(); + for(unsigned i=0; i<getNumberOfArguments(); ++i) { + (getPntrToArgument(i)->getPntrToAction())->turnOnDerivatives(); } turnOnDerivatives(); } -void Bias::registerKeywords( Keywords& keys ){ +void Bias::registerKeywords( Keywords& keys ) { Action::registerKeywords(keys); ActionPilot::registerKeywords(keys); ActionWithValue::registerKeywords(keys); @@ -57,13 +57,13 @@ void Bias::registerKeywords( Keywords& keys ){ keys.addOutputComponent("bias","default","the instantaneous value of the bias potential"); } -void Bias::apply(){ +void Bias::apply() { const unsigned noa=getNumberOfArguments(); const unsigned ncp=getNumberOfComponents(); - if(onStep()) { + if(onStep()) { double gstr = static_cast<double>(getStride()); - for(unsigned i=0;i<noa;++i) { + for(unsigned i=0; i<noa; ++i) { getPntrToArgument(i)->addForce(gstr*outputForces[i]); } } @@ -73,18 +73,18 @@ void Bias::apply(){ std::vector<double> forces(noa); bool at_least_one_forced=false; - for(unsigned i=0;i<ncp;++i){ - if(getPntrToComponent(i)->applyForce(forces)){ - at_least_one_forced=true; - for(unsigned j=0;j<noa;j++) f[j]+=forces[j]; + for(unsigned i=0; i<ncp; ++i) { + if(getPntrToComponent(i)->applyForce(forces)) { + at_least_one_forced=true; + for(unsigned j=0; j<noa; j++) f[j]+=forces[j]; } } if(at_least_one_forced && !onStep()) error("you are biasing a bias with an inconsistent STRIDE"); - if(at_least_one_forced) for(unsigned i=0;i<noa;++i){ - getPntrToArgument(i)->addForce(f[i]); - } + if(at_least_one_forced) for(unsigned i=0; i<noa; ++i) { + getPntrToArgument(i)->addForce(f[i]); + } } diff --git a/src/bias/Bias.h b/src/bias/Bias.h index 551372dec..25776466f 100644 --- a/src/bias/Bias.h +++ b/src/bias/Bias.h @@ -28,12 +28,12 @@ #define PLUMED_BIAS_INIT(ao) Action(ao),Bias(ao) -namespace PLMD{ -namespace bias{ +namespace PLMD { +namespace bias { /** \ingroup INHERIT -This is the abstract base class to use for implementing new simulation biases, within it there is +This is the abstract base class to use for implementing new simulation biases, within it there is information as to how to go about implementing a new bias. */ @@ -59,18 +59,18 @@ public: }; inline -void Bias::setOutputForce(int i,double f){ +void Bias::setOutputForce(int i,double f) { outputForces[i]=f; valueBias->addDerivative(i,-f); } inline -void Bias::setBias(double bias){ - valueBias->set(bias); +void Bias::setBias(double bias) { + valueBias->set(bias); } inline -unsigned Bias::getNumberOfDerivatives(){ +unsigned Bias::getNumberOfDerivatives() { return getNumberOfArguments(); } diff --git a/src/bias/BiasValue.cpp b/src/bias/BiasValue.cpp index 4d5e3e25b..3e77621a5 100644 --- a/src/bias/BiasValue.cpp +++ b/src/bias/BiasValue.cpp @@ -26,10 +26,10 @@ using namespace std; -namespace PLMD{ -namespace bias{ +namespace PLMD { +namespace bias { -//+PLUMEDOC BIAS BIASVALUE +//+PLUMEDOC BIAS BIASVALUE /* Takes the value of one variable and use it as a bias @@ -40,7 +40,7 @@ to some collective variable then using the value of this function directly as a \par Examples The following input tells plumed to use the value of the distance between atoms 3 and 5 -and the value of the distance between atoms 2 and 4 as biases. +and the value of the distance between atoms 2 and 4 as biases. It then tells plumed to print the energy of the restraint \verbatim DISTANCE ATOMS=3,5 LABEL=d1 @@ -50,13 +50,13 @@ PRINT ARG=d1,d2,b.d1,b.d2 \endverbatim (See also \ref DISTANCE and \ref PRINT). -Another thing one can do is asking one system to follow +Another thing one can do is asking one system to follow a circle in sin/cos according a time dependence \verbatim t: TIME # this just print cos and sin of time -cos: MATHEVAL ARG=t VAR=t FUNC=cos(t) PERIODIC=NO +cos: MATHEVAL ARG=t VAR=t FUNC=cos(t) PERIODIC=NO sin: MATHEVAL ARG=t VAR=t FUNC=sin(t) PERIODIC=NO c1: COM ATOMS=1,2 c2: COM ATOMS=3,4 @@ -65,11 +65,11 @@ PRINT ARG=t,cos,sin,d.x,d.y,d.z STRIDE=1 FILE=colvar FMT=%8.4f # this calculates sine and cosine of a projected component of distance mycos: MATHEVAL ARG=d.x,d.y VAR=x,y FUNC=x/sqrt(x*x+y*y) PERIODIC=NO mysin: MATHEVAL ARG=d.x,d.y VAR=x,y FUNC=y/sqrt(x*x+y*y) PERIODIC=NO -# this creates a moving spring so that the system follows a circle-like dynamics +# this creates a moving spring so that the system follows a circle-like dynamics # but it is not a bias, it is a simple value now vv1: MATHEVAL ARG=mycos,mysin,cos,sin VAR=mc,ms,c,s FUNC=100*((mc-c)^2+(ms-s)^2) PERIODIC=NO -# this takes the value calculated with matheval and uses as a bias -cc: BIASVALUE ARG=vv1 +# this takes the value calculated with matheval and uses as a bias +cc: BIASVALUE ARG=vv1 # some printout PRINT ARG=t,cos,sin,d.x,d.y,d.z,mycos,mysin,cc.bias.vv1 STRIDE=1 FILE=colvar FMT=%8.4f \endverbatim @@ -79,7 +79,7 @@ PRINT ARG=t,cos,sin,d.x,d.y,d.z,mycos,mysin,cc.bias.vv1 STRIDE=1 FILE=colvar FMT */ //+ENDPLUMEDOC -class BiasValue : public Bias{ +class BiasValue : public Bias { public: explicit BiasValue(const ActionOptions&); void calculate(); @@ -88,31 +88,31 @@ public: PLUMED_REGISTER_ACTION(BiasValue,"BIASVALUE") -void BiasValue::registerKeywords(Keywords& keys){ +void BiasValue::registerKeywords(Keywords& keys) { Bias::registerKeywords(keys); keys.use("ARG"); // Should be _bias below keys.addOutputComponent("_bias","default","one or multiple instances of this quantity will be refereceable elsewhere in the input file. " - "these quantities will named with the arguments of the bias followed by " - "the character string _bias. These quantities tell the user how much the bias is " - "due to each of the colvars."); + "these quantities will named with the arguments of the bias followed by " + "the character string _bias. These quantities tell the user how much the bias is " + "due to each of the colvars."); } BiasValue::BiasValue(const ActionOptions&ao): -PLUMED_BIAS_INIT(ao) + PLUMED_BIAS_INIT(ao) { checkRead(); - // add one bias for each argument - for(unsigned i=0;i<getNumberOfArguments();++i){ + // add one bias for each argument + for(unsigned i=0; i<getNumberOfArguments(); ++i) { string ss=getPntrToArgument(i)->getName()+"_bias"; addComponent(ss); componentIsNotPeriodic(ss); } } -void BiasValue::calculate(){ +void BiasValue::calculate() { double bias=0.0; - for(unsigned i=0;i<getNumberOfArguments();++i){ - double val; val=getArgument(i); + for(unsigned i=0; i<getNumberOfArguments(); ++i) { + double val; val=getArgument(i); getPntrToComponent(i+1)->set(val); setOutputForce(i,-1.); bias+=val; diff --git a/src/bias/ExtendedLagrangian.cpp b/src/bias/ExtendedLagrangian.cpp index 1b89116a2..85de570dd 100644 --- a/src/bias/ExtendedLagrangian.cpp +++ b/src/bias/ExtendedLagrangian.cpp @@ -31,8 +31,8 @@ using namespace std; -namespace PLMD{ -namespace bias{ +namespace PLMD { +namespace bias { //+PLUMEDOC BIAS EXTENDED_LAGRANGIAN /* @@ -114,7 +114,7 @@ PRINT STRIDE=10 ARG=phi,psi,ex.phi_fict,ex.psi_fict FILE=COLVAR */ //+ENDPLUMEDOC -class ExtendedLagrangian : public Bias{ +class ExtendedLagrangian : public Bias { bool firsttime; std::vector<double> fict; std::vector<double> vfict; @@ -136,35 +136,35 @@ public: PLUMED_REGISTER_ACTION(ExtendedLagrangian,"EXTENDED_LAGRANGIAN") -void ExtendedLagrangian::registerKeywords(Keywords& keys){ - Bias::registerKeywords(keys); - keys.use("ARG"); - keys.add("compulsory","KAPPA","specifies that the restraint is harmonic and what the values of the force constants on each of the variables are"); - keys.add("compulsory","TAU","specifies that the restraint is harmonic and what the values of the force constants on each of the variables are"); - keys.add("compulsory","FRICTION","0.0","add a friction to the variable"); - keys.add("optional","TEMP","the system temperature - needed when FRICTION is present. If not provided will be taken from MD code (if available)"); - componentsAreNotOptional(keys); - keys.addOutputComponent("_fict","default","one or multiple instances of this quantity will be refereceable elsewhere in the input file. " - "These quantities will named with the arguments of the bias followed by " - "the character string _tilde. It is possible to add forces on these variable."); - keys.addOutputComponent("_vfict","default","one or multiple instances of this quantity will be refereceable elsewhere in the input file. " - "These quantities will named with the arguments of the bias followed by " - "the character string _tilde. It is NOT possible to add forces on these variable."); +void ExtendedLagrangian::registerKeywords(Keywords& keys) { + Bias::registerKeywords(keys); + keys.use("ARG"); + keys.add("compulsory","KAPPA","specifies that the restraint is harmonic and what the values of the force constants on each of the variables are"); + keys.add("compulsory","TAU","specifies that the restraint is harmonic and what the values of the force constants on each of the variables are"); + keys.add("compulsory","FRICTION","0.0","add a friction to the variable"); + keys.add("optional","TEMP","the system temperature - needed when FRICTION is present. If not provided will be taken from MD code (if available)"); + componentsAreNotOptional(keys); + keys.addOutputComponent("_fict","default","one or multiple instances of this quantity will be refereceable elsewhere in the input file. " + "These quantities will named with the arguments of the bias followed by " + "the character string _tilde. It is possible to add forces on these variable."); + keys.addOutputComponent("_vfict","default","one or multiple instances of this quantity will be refereceable elsewhere in the input file. " + "These quantities will named with the arguments of the bias followed by " + "the character string _tilde. It is NOT possible to add forces on these variable."); } ExtendedLagrangian::ExtendedLagrangian(const ActionOptions&ao): -PLUMED_BIAS_INIT(ao), -firsttime(true), -fict(getNumberOfArguments(),0.0), -vfict(getNumberOfArguments(),0.0), -vfict_laststep(getNumberOfArguments(),0.0), -ffict(getNumberOfArguments(),0.0), -kappa(getNumberOfArguments(),0.0), -tau(getNumberOfArguments(),0.0), -friction(getNumberOfArguments(),0.0), -fictValue(getNumberOfArguments(),NULL), -vfictValue(getNumberOfArguments(),NULL), -kbt(0.0) + PLUMED_BIAS_INIT(ao), + firsttime(true), + fict(getNumberOfArguments(),0.0), + vfict(getNumberOfArguments(),0.0), + vfict_laststep(getNumberOfArguments(),0.0), + ffict(getNumberOfArguments(),0.0), + kappa(getNumberOfArguments(),0.0), + tau(getNumberOfArguments(),0.0), + friction(getNumberOfArguments(),0.0), + fictValue(getNumberOfArguments(),NULL), + vfictValue(getNumberOfArguments(),NULL), + kbt(0.0) { parseVector("TAU",tau); parseVector("FRICTION",friction); @@ -176,19 +176,19 @@ kbt(0.0) checkRead(); log.printf(" with harmonic force constant"); - for(unsigned i=0;i<kappa.size();i++) log.printf(" %f",kappa[i]); + for(unsigned i=0; i<kappa.size(); i++) log.printf(" %f",kappa[i]); log.printf("\n"); log.printf(" with relaxation time"); - for(unsigned i=0;i<tau.size();i++) log.printf(" %f",tau[i]); + for(unsigned i=0; i<tau.size(); i++) log.printf(" %f",tau[i]); log.printf("\n"); bool hasFriction=false; - for(unsigned i=0;i<getNumberOfArguments();++i) if(friction[i]>0.0) hasFriction=true; + for(unsigned i=0; i<getNumberOfArguments(); ++i) if(friction[i]>0.0) hasFriction=true; - if(hasFriction){ + if(hasFriction) { log.printf(" with friction"); - for(unsigned i=0;i<friction.size();i++) log.printf(" %f",friction[i]); + for(unsigned i=0; i<friction.size(); i++) log.printf(" %f",friction[i]); log.printf("\n"); } @@ -196,10 +196,10 @@ kbt(0.0) log.printf(" %f",kbt); log.printf("\n"); - for(unsigned i=0;i<getNumberOfArguments();i++){ + for(unsigned i=0; i<getNumberOfArguments(); i++) { std::string comp=getPntrToArgument(i)->getName()+"_fict"; addComponentWithDerivatives(comp); - if(getPntrToArgument(i)->isPeriodic()){ + if(getPntrToArgument(i)->isPeriodic()) { std::string a,b; getPntrToArgument(i)->getDomain(a,b); componentIsPeriodic(comp,a,b); @@ -212,7 +212,7 @@ kbt(0.0) } log<<" Bibliography "<<plumed.cite("Iannuzzi, Laio, and Parrinello, Phys. Rev. Lett. 90, 238302 (2003)"); - if(hasFriction){ + if(hasFriction) { log<<plumed.cite("Maragliano and Vanden-Eijnden, Chem. Phys. Lett. 426, 168 (2006)"); log<<plumed.cite("Abrams and Tuckerman, J. Phys. Chem. B 112, 15742 (2008)"); } @@ -220,16 +220,16 @@ kbt(0.0) } -void ExtendedLagrangian::calculate(){ +void ExtendedLagrangian::calculate() { - if(firsttime){ - for(unsigned i=0;i<getNumberOfArguments();++i){ + if(firsttime) { + for(unsigned i=0; i<getNumberOfArguments(); ++i) { fict[i]=getArgument(i); } firsttime=false; } double ene=0.0; - for(unsigned i=0;i<getNumberOfArguments();++i){ + for(unsigned i=0; i<getNumberOfArguments(); ++i) { const double cv=difference(i,fict[i],getArgument(i)); const double k=kappa[i]; const double f=-k*cv; @@ -238,16 +238,16 @@ void ExtendedLagrangian::calculate(){ ffict[i]=-f; }; setBias(ene); - for(unsigned i=0;i<getNumberOfArguments();++i){ + for(unsigned i=0; i<getNumberOfArguments(); ++i) { fict[i]=fictValue[i]->bringBackInPbc(fict[i]); fictValue[i]->set(fict[i]); vfictValue[i]->set(vfict_laststep[i]); } } -void ExtendedLagrangian::update(){ +void ExtendedLagrangian::update() { double dt=getTimeStep()*getStride(); - for(unsigned i=0;i<getNumberOfArguments();++i){ + for(unsigned i=0; i<getNumberOfArguments(); ++i) { double mass=kappa[i]*tau[i]*tau[i]/(4*pi*pi); // should be k/omega**2 double c1=exp(-0.5*friction[i]*dt); double c2=sqrt(kbt*(1.0-c1*c1)/mass); diff --git a/src/bias/External.cpp b/src/bias/External.cpp index 51093f66d..62bc54cf9 100644 --- a/src/bias/External.cpp +++ b/src/bias/External.cpp @@ -29,10 +29,10 @@ using namespace std; -namespace PLMD{ -namespace bias{ +namespace PLMD { +namespace bias { -//+PLUMEDOC BIAS EXTERNAL +//+PLUMEDOC BIAS EXTERNAL /* Calculate a restraint that is defined on a grid that is read during start up @@ -41,7 +41,7 @@ The following is an input for a calculation with an external potential that is defined in the file bias.dat and that acts on the distance between atoms 3 and 5. \verbatim DISTANCE ATOMS=3,5 LABEL=d1 -EXTERNAL ARG=d1 FILE=bias.dat LABEL=external +EXTERNAL ARG=d1 FILE=bias.dat LABEL=external \endverbatim (See also \ref DISTANCE \ref PRINT). @@ -56,9 +56,9 @@ The header in the file bias.dat should read: This should then be followed by the value of the potential and its derivative at 100 equally spaced points along the distance between 0 and 1. If you run -with NOSPLINE you do not need to provide derivative information. +with NOSPLINE you do not need to provide derivative information. -You can also include grids that are a function of more than one collective +You can also include grids that are a function of more than one collective variable. For instance the following would be the input for an external potential acting on two torsional angles: \verbatim @@ -81,23 +81,23 @@ The header in the file bias.dat for this calculation would read: \endverbatim This would be then followed by 100 blocks of data. In the first block of data the -value of t1 (the value in the first column) is kept fixed and the value of +value of t1 (the value in the first column) is kept fixed and the value of the function is given at 100 equally spaced values for t2 between \f$-pi\f$ and \f$+pi\f$. In the second block of data t1 is fixed at \f$-pi + \frac{2pi}{100}\f$ and the value of the function is given at 100 equally spaced values for t2 between \f$-pi\f$ and \f$+pi\f$. In the third block of -data the same is done but t1 is fixed at \f$-pi + \frac{4pi}{100}\f$ and so on untill you get to -the 100th block of data where t1 is fixed at \f$+pi\f$. +data the same is done but t1 is fixed at \f$-pi + \frac{4pi}{100}\f$ and so on untill you get to +the 100th block of data where t1 is fixed at \f$+pi\f$. Please note the order that the order of arguments in the plumed.dat file must be the same as the order of arguments in the header of the grid file. */ //+ENDPLUMEDOC -class External : public Bias{ +class External : public Bias { private: Grid* BiasGrid_; - + public: explicit External(const ActionOptions&); ~External(); @@ -107,7 +107,7 @@ public: PLUMED_REGISTER_ACTION(External,"EXTERNAL") -void External::registerKeywords(Keywords& keys){ +void External::registerKeywords(Keywords& keys) { Bias::registerKeywords(keys); keys.use("ARG"); keys.add("compulsory","FILE","the name of the file containing the external potential."); @@ -115,17 +115,17 @@ void External::registerKeywords(Keywords& keys){ keys.addFlag("SPARSE",false,"specifies that the external potential uses a sparse grid"); } -External::~External(){ +External::~External() { delete BiasGrid_; } External::External(const ActionOptions& ao): -PLUMED_BIAS_INIT(ao), -BiasGrid_(NULL) + PLUMED_BIAS_INIT(ao), + BiasGrid_(NULL) { string filename; parse("FILE",filename); - if( filename.length()==0 ) error("No external potential file was specified"); + if( filename.length()==0 ) error("No external potential file was specified"); bool sparsegrid=false; parseFlag("SPARSE",sparsegrid); bool nospline=false; @@ -135,18 +135,18 @@ BiasGrid_(NULL) checkRead(); log.printf(" External potential from file %s\n",filename.c_str()); - if(spline){log.printf(" External potential uses spline interpolation\n");} - if(sparsegrid){log.printf(" External potential uses sparse grid\n");} - + if(spline) {log.printf(" External potential uses spline interpolation\n");} + if(sparsegrid) {log.printf(" External potential uses sparse grid\n");} + // read grid IFile gridfile; gridfile.open(filename); - std::string funcl=getLabel() + ".bias"; + std::string funcl=getLabel() + ".bias"; BiasGrid_=Grid::create(funcl,getArguments(),gridfile,sparsegrid,spline,true); gridfile.close(); if(BiasGrid_->getDimension()!=getNumberOfArguments()) error("mismatch between dimensionality of input grid and number of arguments"); - for(unsigned i=0;i<getNumberOfArguments();++i){ - if( getPntrToArgument(i)->isPeriodic()!=BiasGrid_->getIsPeriodic()[i] ) error("periodicity mismatch between arguments and input bias"); - } + for(unsigned i=0; i<getNumberOfArguments(); ++i) { + if( getPntrToArgument(i)->isPeriodic()!=BiasGrid_->getIsPeriodic()[i] ) error("periodicity mismatch between arguments and input bias"); + } } void External::calculate() @@ -154,13 +154,13 @@ void External::calculate() unsigned ncv=getNumberOfArguments(); vector<double> cv(ncv), der(ncv); - for(unsigned i=0;i<ncv;++i){cv[i]=getArgument(i);} + for(unsigned i=0; i<ncv; ++i) {cv[i]=getArgument(i);} double ene=BiasGrid_->getValueAndDerivatives(cv,der); setBias(ene); - for(unsigned i=0;i<ncv;++i){ + for(unsigned i=0; i<ncv; ++i) { const double f=-der[i]; setOutputForce(i,f); } diff --git a/src/bias/LWalls.cpp b/src/bias/LWalls.cpp index c286c28a7..33d7f7c04 100644 --- a/src/bias/LWalls.cpp +++ b/src/bias/LWalls.cpp @@ -26,16 +26,16 @@ using namespace std; -namespace PLMD{ -namespace bias{ +namespace PLMD { +namespace bias { //+PLUMEDOC BIAS LOWER_WALLS /* Defines a wall for the value of one or more collective variables, - which limits the region of the phase space accessible during the simulation. + which limits the region of the phase space accessible during the simulation. -The restraining potential starts acting on the system when the value of the CV is greater -(in the case of UPPER_WALLS) or lower (in the case of LOWER_WALLS) than a certain limit \f$a_i\f$ (AT) +The restraining potential starts acting on the system when the value of the CV is greater +(in the case of UPPER_WALLS) or lower (in the case of LOWER_WALLS) than a certain limit \f$a_i\f$ (AT) minus an offset \f$o_i\f$ (OFFSET). The expression for the bias due to the wall is given by: @@ -43,15 +43,15 @@ The expression for the bias due to the wall is given by: \sum_i {k_i}((x_i-a_i+o_i)/s_i)^e_i \f$ -\f$k_i\f$ (KAPPA) is an energy constant in internal unit of the code, \f$s_i\f$ (EPS) a rescaling factor and +\f$k_i\f$ (KAPPA) is an energy constant in internal unit of the code, \f$s_i\f$ (EPS) a rescaling factor and \f$e_i\f$ (EXP) the exponent determining the power law. By default: EXP = 2, EPS = 1.0, OFFSET = 0. \par Examples -The following input tells plumed to add both a lower and an upper walls on the distance +The following input tells plumed to add both a lower and an upper walls on the distance between atoms 3 and 5 and the distance between atoms 2 and 4. The lower and upper limits -are defined at different values. The strength of the walls is the same for the four cases. -It also tells plumed to print the energy of the walls. +are defined at different values. The strength of the walls is the same for the four cases. +It also tells plumed to print the energy of the walls. \verbatim DISTANCE ATOMS=3,5 LABEL=d1 DISTANCE ATOMS=2,4 LABEL=d2 @@ -64,7 +64,7 @@ PRINT ARG=uwall.bias,lwall.bias */ //+ENDPLUMEDOC -class LWalls : public Bias{ +class LWalls : public Bias { std::vector<double> at; std::vector<double> kappa; std::vector<double> exp; @@ -78,7 +78,7 @@ public: PLUMED_REGISTER_ACTION(LWalls,"LOWER_WALLS") -void LWalls::registerKeywords(Keywords& keys){ +void LWalls::registerKeywords(Keywords& keys) { Bias::registerKeywords(keys); keys.use("ARG"); keys.add("compulsory","AT","the positions of the wall. The a_i in the expression for a wall."); @@ -90,12 +90,12 @@ void LWalls::registerKeywords(Keywords& keys){ } LWalls::LWalls(const ActionOptions&ao): -PLUMED_BIAS_INIT(ao), -at(getNumberOfArguments(),0), -kappa(getNumberOfArguments(),0.0), -exp(getNumberOfArguments(),2.0), -eps(getNumberOfArguments(),1.0), -offset(getNumberOfArguments(),0.0) + PLUMED_BIAS_INIT(ao), + at(getNumberOfArguments(),0), + kappa(getNumberOfArguments(),0.0), + exp(getNumberOfArguments(),2.0), + eps(getNumberOfArguments(),1.0), + offset(getNumberOfArguments(),0.0) { // Note sizes of these vectors are automatically checked by parseVector :-) parseVector("OFFSET",offset); @@ -106,28 +106,28 @@ offset(getNumberOfArguments(),0.0) checkRead(); log.printf(" at"); - for(unsigned i=0;i<at.size();i++) log.printf(" %f",at[i]); + for(unsigned i=0; i<at.size(); i++) log.printf(" %f",at[i]); log.printf("\n"); log.printf(" with an offset"); - for(unsigned i=0;i<offset.size();i++) log.printf(" %f",offset[i]); + for(unsigned i=0; i<offset.size(); i++) log.printf(" %f",offset[i]); log.printf("\n"); log.printf(" with force constant"); - for(unsigned i=0;i<kappa.size();i++) log.printf(" %f",kappa[i]); + for(unsigned i=0; i<kappa.size(); i++) log.printf(" %f",kappa[i]); log.printf("\n"); log.printf(" and exponent"); - for(unsigned i=0;i<exp.size();i++) log.printf(" %f",exp[i]); + for(unsigned i=0; i<exp.size(); i++) log.printf(" %f",exp[i]); log.printf("\n"); log.printf(" rescaled"); - for(unsigned i=0;i<eps.size();i++) log.printf(" %f",eps[i]); + for(unsigned i=0; i<eps.size(); i++) log.printf(" %f",eps[i]); log.printf("\n"); addComponent("force2"); componentIsNotPeriodic("force2"); } -void LWalls::calculate(){ +void LWalls::calculate() { double ene = 0.0; double totf2 = 0.0; - for(unsigned i=0;i<getNumberOfArguments();++i){ + for(unsigned i=0; i<getNumberOfArguments(); ++i) { const double cv=difference(i,at[i],getArgument(i)); const double k=kappa[i]; const double exponent=exp[i]; @@ -138,13 +138,13 @@ void LWalls::calculate(){ if( lscale < 0.) { double power = pow( lscale, exponent ); f = -( k / epsilon ) * exponent * power / lscale; - ene += k * power; + ene += k * power; totf2 += f * f; } setOutputForce(i,f); } setBias(ene); - getPntrToComponent("force2")->set(totf2); + getPntrToComponent("force2")->set(totf2); } } diff --git a/src/bias/MetaD.cpp b/src/bias/MetaD.cpp index 6e9923aaa..b58618570 100644 --- a/src/bias/MetaD.cpp +++ b/src/bias/MetaD.cpp @@ -41,14 +41,14 @@ using namespace std; -namespace PLMD{ -namespace bias{ +namespace PLMD { +namespace bias { -//+PLUMEDOC BIAS METAD +//+PLUMEDOC BIAS METAD /* Used to performed MetaDynamics on one or more collective variables. -In a metadynamics simulations a history dependent bias composed of +In a metadynamics simulations a history dependent bias composed of intermittently added Gaussian functions is added to the potential \cite metad. \f[ @@ -60,10 +60,10 @@ V(\vec{s},t) = \sum_{ k \tau < t} W(k \tau) This potential forces the system away from the kinetic traps in the potential energy surface and out into the unexplored parts of the energy landscape. Information on the Gaussian -functions from which this potential is composed is output to a file called HILLS, which -is used both the restart the calculation and to reconstruct the free energy as a function of the CVs. +functions from which this potential is composed is output to a file called HILLS, which +is used both the restart the calculation and to reconstruct the free energy as a function of the CVs. The free energy can be reconstructed from a metadynamics calculation because the final bias is given -by: +by: \f[ V(\vec{s}) = -F(\vec(s)) @@ -72,10 +72,10 @@ V(\vec{s}) = -F(\vec(s)) During post processing the free energy can be calculated in this way using the \ref sum_hills utility. -In the simplest possible implementation of a metadynamics calculation the expense of a metadynamics -calculation increases with the length of the simulation as one has to, at every step, evaluate +In the simplest possible implementation of a metadynamics calculation the expense of a metadynamics +calculation increases with the length of the simulation as one has to, at every step, evaluate the values of a larger and larger number of Gaussians. To avoid this issue you can -store the bias on a grid. This approach is similar to that proposed in \cite babi08jcp but has the +store the bias on a grid. This approach is similar to that proposed in \cite babi08jcp but has the advantage that the grid spacing is independent on the Gaussian width. Notice that you should provide either the number of bins for every collective variable (GRID_BIN) or @@ -112,19 +112,19 @@ gaussian potential is denoted by one value only that is a Cartesian space (ADAPT (ADAPTIVE=DIFF). Note that a specific integration technique for the deposited gaussians should be used in this case. Check the documentation for utility sum_hills. -With the keyword INTERVAL one changes the metadynamics algorithm setting the bias force equal to zero -outside boundary \cite baftizadeh2012protein. If, for example, metadynamics is performed on a CV s and one is interested only +With the keyword INTERVAL one changes the metadynamics algorithm setting the bias force equal to zero +outside boundary \cite baftizadeh2012protein. If, for example, metadynamics is performed on a CV s and one is interested only to the free energy for s > sw, the history dependent potential is still updated according to the above -equations but the metadynamics force is set to zero for s < sw. Notice that Gaussians are added also -if s < sw, as the tails of these Gaussians influence VG in the relevant region s > sw. In this way, the -force on the system in the region s > sw comes from both metadynamics and the force field, in the region -s < sw only from the latter. This approach allows obtaining a history-dependent bias potential VG that -fluctuates around a stable estimator, equal to the negative of the free energy far enough from the +equations but the metadynamics force is set to zero for s < sw. Notice that Gaussians are added also +if s < sw, as the tails of these Gaussians influence VG in the relevant region s > sw. In this way, the +force on the system in the region s > sw comes from both metadynamics and the force field, in the region +s < sw only from the latter. This approach allows obtaining a history-dependent bias potential VG that +fluctuates around a stable estimator, equal to the negative of the free energy far enough from the boundaries. Note that: - It works only for one-dimensional biases; - It works both with and without GRID; - The interval limit sw in a region where the free energy derivative is not large; -- If in the region outside the limit sw the system has a free energy minimum, the INTERVAL keyword should +- If in the region outside the limit sw the system has a free energy minimum, the INTERVAL keyword should be used together with a \ref UPPER_WALLS or \ref LOWER_WALLS at sw. As a final note, since version 2.0.2 when the system is outside of the selected interval the force @@ -134,21 +134,21 @@ for replica exchange methods to be computed correctly. Multiple walkers \cite multiplewalkers can also be used. See below the examples. -The c(t) reweighting factor can also be calculated on the fly using the equations -presented in \cite Tiwary_jp504920s. -The expression used to calculate c(t) follows directly from using Eq. 12 in -Eq. 3 in \cite Tiwary_jp504920s and gives smoother results than equivalent Eqs. 13 -and Eqs. 14 in that paper. The c(t) is given by the rct component while the bias -normalized by c(t) is given by the rbias component (rbias=bias-ct) which can be used +The c(t) reweighting factor can also be calculated on the fly using the equations +presented in \cite Tiwary_jp504920s. +The expression used to calculate c(t) follows directly from using Eq. 12 in +Eq. 3 in \cite Tiwary_jp504920s and gives smoother results than equivalent Eqs. 13 +and Eqs. 14 in that paper. The c(t) is given by the rct component while the bias +normalized by c(t) is given by the rbias component (rbias=bias-ct) which can be used to obtain a reweighted histogram. -The calculation of c(t) is enabled by using the keyword REWEIGHTING_NGRID where the grid used for the +The calculation of c(t) is enabled by using the keyword REWEIGHTING_NGRID where the grid used for the calculation is specified. This grid should have a size that is equal or larger than the grid given in GRID_BIN./ -By default c(t) is updated every 50 Gaussian hills but this -can be changed by using the REWEIGHTING_NHILLS keyword. -This option can only be employed together with Well-Tempered Metadynamics and requires that +By default c(t) is updated every 50 Gaussian hills but this +can be changed by using the REWEIGHTING_NHILLS keyword. +This option can only be employed together with Well-Tempered Metadynamics and requires that a grid is used. -Additional material and examples can be also found in the tutorials: +Additional material and examples can be also found in the tutorials: - \ref belfast-6 - \ref belfast-7 @@ -174,7 +174,7 @@ PRINT ARG=d1,d2,restraint.bias STRIDE=100 FILE=COLVAR \par If you use adaptive Gaussians, with diffusion scheme where you use a Gaussian that should cover the space of 20 timesteps in collective variables. -Note that in this case the histogram correction is needed when summing up hills. +Note that in this case the histogram correction is needed when summing up hills. \verbatim DISTANCE ATOMS=3,5 LABEL=d1 DISTANCE ATOMS=2,4 LABEL=d2 @@ -185,7 +185,7 @@ PRINT ARG=d1,d2,restraint.bias STRIDE=100 FILE=COLVAR \par If you use adaptive Gaussians, with geometrical scheme where you use a Gaussian that should cover the space of 0.05 nm in Cartesian space. -Note that in this case the histogram correction is needed when summing up hills. +Note that in this case the histogram correction is needed when summing up hills. \verbatim DISTANCE ATOMS=3,5 LABEL=d1 DISTANCE ATOMS=2,4 LABEL=d2 @@ -194,40 +194,40 @@ PRINT ARG=d1,d2,restraint.bias STRIDE=100 FILE=COLVAR \endverbatim \par -When using adaptive Gaussians you might want to limit how the hills width can change. +When using adaptive Gaussians you might want to limit how the hills width can change. You can use SIGMA_MIN and SIGMA_MAX keywords. -The sigmas should specified in terms of CV so you should use the CV units. +The sigmas should specified in terms of CV so you should use the CV units. Note that if you use a negative number, this means that the limit is not set. -Note also that in this case the histogram correction is needed when summing up hills. +Note also that in this case the histogram correction is needed when summing up hills. \verbatim DISTANCE ATOMS=3,5 LABEL=d1 DISTANCE ATOMS=2,4 LABEL=d2 METAD ... ARG=d1,d2 SIGMA=0.05 HEIGHT=0.3 PACE=500 LABEL=restraint ADAPTIVE=GEOM - SIGMA_MIN=0.2,0.1 SIGMA_MAX=0.5,1.0 -... METAD + SIGMA_MIN=0.2,0.1 SIGMA_MAX=0.5,1.0 +... METAD PRINT ARG=d1,d2,restraint.bias STRIDE=100 FILE=COLVAR \endverbatim \par -Multiple walkers can be also use as in \cite multiplewalkers -These are enabled by setting the number of walker used, the id of the -current walker which interprets the input file, the directory where the +Multiple walkers can be also use as in \cite multiplewalkers +These are enabled by setting the number of walker used, the id of the +current walker which interprets the input file, the directory where the hills containing files resides, and the frequency to read the other walkers. Here is an example \verbatim DISTANCE ATOMS=3,5 LABEL=d1 METAD ... - ARG=d1 SIGMA=0.05 HEIGHT=0.3 PACE=500 LABEL=restraint + ARG=d1 SIGMA=0.05 HEIGHT=0.3 PACE=500 LABEL=restraint WALKERS_N=10 WALKERS_ID=3 WALKERS_DIR=../ WALKERS_RSTRIDE=100 ... METAD \endverbatim -where WALKERS_N is the total number of walkers, WALKERS_ID is the -id of the present walker (starting from 0 ) and the WALKERS_DIR is the directory -where all the walkers are located. WALKERS_RSTRIDE is the number of step between +where WALKERS_N is the total number of walkers, WALKERS_ID is the +id of the present walker (starting from 0 ) and the WALKERS_DIR is the directory +where all the walkers are located. WALKERS_RSTRIDE is the number of step between one update and the other. Since version 2.2.5, hills files are automatically flushed every WALKERS_RSTRIDE steps. @@ -331,20 +331,20 @@ The number of elements in the RECT array should be equal to the number of replic */ //+ENDPLUMEDOC -class MetaD : public Bias{ +class MetaD : public Bias { private: struct Gaussian { - vector<double> center; - vector<double> sigma; - double height; - bool multivariate; // this is required to discriminate the one dimensional case - vector<double> invsigma; - Gaussian(const vector<double> & center,const vector<double> & sigma,double height, bool multivariate ): - center(center),sigma(sigma),height(height),multivariate(multivariate),invsigma(sigma){ - // to avoid troubles from zero element in flexible hills - for(unsigned i=0;i<invsigma.size();++i) abs(invsigma[i])>1.e-20?invsigma[i]=1.0/invsigma[i]:0.; - } + vector<double> center; + vector<double> sigma; + double height; + bool multivariate; // this is required to discriminate the one dimensional case + vector<double> invsigma; + Gaussian(const vector<double> & center,const vector<double> & sigma,double height, bool multivariate ): + center(center),sigma(sigma),height(height),multivariate(multivariate),invsigma(sigma) { + // to avoid troubles from zero element in flexible hills + for(unsigned i=0; i<invsigma.size(); ++i) abs(invsigma[i])>1.e-20?invsigma[i]=1.0/invsigma[i]:0.; + } }; vector<double> sigma0_; vector<double> sigma0min_; @@ -354,7 +354,7 @@ private: OFile gridfile_; Grid* BiasGrid_; bool storeOldGrids_; - int wgridstride_; + int wgridstride_; bool grid_; double height0_; double biasf_; @@ -383,11 +383,11 @@ private: bool doInt_; bool isFirstStep; double reweight_factor; - vector<unsigned> rewf_grid_; + vector<unsigned> rewf_grid_; unsigned rewf_ustride_; double work_; long int last_step_warn_grid; - + void readGaussians(IFile*); bool readChunkOfGaussians(IFile *ifile, unsigned n); void writeGaussian(const Gaussian&,OFile&); @@ -407,15 +407,15 @@ public: void calculate(); void update(); static void registerKeywords(Keywords& keys); - bool checkNeedsGradients()const{if(adaptive_==FlexibleBin::geometry){return true;}else{return false;}} + bool checkNeedsGradients()const {if(adaptive_==FlexibleBin::geometry) {return true;} else {return false;}} }; PLUMED_REGISTER_ACTION(MetaD,"METAD") -void MetaD::registerKeywords(Keywords& keys){ +void MetaD::registerKeywords(Keywords& keys) { Bias::registerKeywords(keys); keys.addOutputComponent("rbias","REWEIGHTING_NGRID","the instantaneous value of the bias normalized using the \\f$c(t)\\f$ reweighting factor [rbias=bias-c(t)]." - "This component can be used to obtain a reweighted histogram."); + "This component can be used to obtain a reweighted histogram."); keys.addOutputComponent("rct","REWEIGHTING_NGRID","the reweighting factor \\f$c(t)\\f$."); keys.addOutputComponent("work","default","accumulator for work"); keys.addOutputComponent("acc","ACCELERATION","the metadynamics acceleration factor"); @@ -436,11 +436,11 @@ void MetaD::registerKeywords(Keywords& keys){ keys.add("optional","GRID_BIN","the number of bins for the grid"); keys.add("optional","GRID_SPACING","the approximate grid spacing (to be used as an alternative or together with GRID_BIN)"); keys.add("optional","REWEIGHTING_NGRID","calculate the c(t) reweighting factor and use that to obtain the normalized bias [rbias=bias-c(t)]." - "Here you should specify the number of grid points required in each dimension." - "The number of grid points should be equal or larger to the number of grid points given in GRID_BIN." - "This method is not compatible with metadynamics not on a grid."); + "Here you should specify the number of grid points required in each dimension." + "The number of grid points should be equal or larger to the number of grid points given in GRID_BIN." + "This method is not compatible with metadynamics not on a grid."); keys.add("optional","REWEIGHTING_NHILLS","how many Gaussian hills should be deposited between calculating the c(t) reweighting factor." - "The default is to do this every 50 hills."); + "The default is to do this every 50 hills."); keys.addFlag("GRID_SPARSE",false,"use a sparse grid to store hills"); keys.addFlag("GRID_NOSPLINE",false,"don't use spline interpolation with grids"); keys.add("optional","GRID_WSTRIDE","write the grid to a file every N steps"); @@ -456,13 +456,13 @@ void MetaD::registerKeywords(Keywords& keys){ keys.add("optional","SIGMA_MAX","the upper bounds for the sigmas (in CV units) when using adaptive hills. Negative number means no bounds "); keys.add("optional","SIGMA_MIN","the lower bounds for the sigmas (in CV units) when using adaptive hills. Negative number means no bounds "); keys.addFlag("WALKERS_MPI",false,"Switch on MPI version of multiple walkers - not compatible with WALKERS_* options other than WALKERS_DIR"); - keys.addFlag("ACCELERATION",false,"Set to TRUE if you want to compute the metadynamics acceleration factor."); + keys.addFlag("ACCELERATION",false,"Set to TRUE if you want to compute the metadynamics acceleration factor."); keys.use("RESTART"); keys.use("UPDATE_FROM"); keys.use("UPDATE_UNTIL"); } -MetaD::~MetaD(){ +MetaD::~MetaD() { if(flexbin) delete flexbin; if(BiasGrid_) delete BiasGrid_; if(TargetGrid_) delete TargetGrid_; @@ -470,86 +470,86 @@ MetaD::~MetaD(){ if(wgridstride_>0) gridfile_.close(); delete [] dp_; // close files - for(int i=0;i<mw_n_;++i){ - if(ifiles[i]->isOpen()) ifiles[i]->close(); - delete ifiles[i]; + for(int i=0; i<mw_n_; ++i) { + if(ifiles[i]->isOpen()) ifiles[i]->close(); + delete ifiles[i]; } } MetaD::MetaD(const ActionOptions& ao): -PLUMED_BIAS_INIT(ao), + PLUMED_BIAS_INIT(ao), // Grid stuff initialization -BiasGrid_(NULL), wgridstride_(0), grid_(false), + BiasGrid_(NULL), wgridstride_(0), grid_(false), // Metadynamics basic parameters -height0_(std::numeric_limits<double>::max()), biasf_(-1.0), dampfactor_(0.0), TargetGrid_(NULL), -kbt_(0.0), -stride_(0), welltemp_(false), + height0_(std::numeric_limits<double>::max()), biasf_(-1.0), dampfactor_(0.0), TargetGrid_(NULL), + kbt_(0.0), + stride_(0), welltemp_(false), // Other stuff -dp_(NULL), adaptive_(FlexibleBin::none), -flexbin(NULL), + dp_(NULL), adaptive_(FlexibleBin::none), + flexbin(NULL), // Multiple walkers initialization -mw_n_(1), mw_dir_(""), mw_id_(0), mw_rstride_(1), -walkers_mpi(false), mpi_nw_(0), mpi_mw_(0), -acceleration(false), acc(0.0), + mw_n_(1), mw_dir_(""), mw_id_(0), mw_rstride_(1), + walkers_mpi(false), mpi_nw_(0), mpi_mw_(0), + acceleration(false), acc(0.0), // Interval initialization -uppI_(-1), lowI_(-1), doInt_(false), -isFirstStep(true), -reweight_factor(0.0), -rewf_ustride_(1), -work_(0), -last_step_warn_grid(0) + uppI_(-1), lowI_(-1), doInt_(false), + isFirstStep(true), + reweight_factor(0.0), + rewf_ustride_(1), + work_(0), + last_step_warn_grid(0) { // parse the flexible hills string adaptiveoption; adaptiveoption="NONE"; parse("ADAPTIVE",adaptiveoption); - if(adaptiveoption=="GEOM"){ + if(adaptiveoption=="GEOM") { log.printf(" Uses Geometry-based hills width: sigma must be in distance units and only one sigma is needed\n"); - adaptive_=FlexibleBin::geometry; - } else if(adaptiveoption=="DIFF"){ + adaptive_=FlexibleBin::geometry; + } else if(adaptiveoption=="DIFF") { log.printf(" Uses Diffusion-based hills width: sigma must be in timesteps and only one sigma is needed\n"); - adaptive_=FlexibleBin::diffusion; - } else if(adaptiveoption=="NONE"){ - adaptive_=FlexibleBin::none; + adaptive_=FlexibleBin::diffusion; + } else if(adaptiveoption=="NONE") { + adaptive_=FlexibleBin::none; } else { - error("I do not know this type of adaptive scheme"); + error("I do not know this type of adaptive scheme"); } parse("FMT",fmt); // parse the sigma parseVector("SIGMA",sigma0_); - if(adaptive_==FlexibleBin::none){ - // if you use normal sigma you need one sigma per argument + if(adaptive_==FlexibleBin::none) { + // if you use normal sigma you need one sigma per argument if( sigma0_.size()!=getNumberOfArguments() ) error("number of arguments does not match number of SIGMA parameters"); } else { - // if you use flexible hills you need one sigma - if(sigma0_.size()!=1){ + // if you use flexible hills you need one sigma + if(sigma0_.size()!=1) { error("If you choose ADAPTIVE you need only one sigma according to your choice of type (GEOM/DIFF)"); - } + } // if adaptive then the number must be an integer - if(adaptive_==FlexibleBin::diffusion){ - if(int(sigma0_[0])-sigma0_[0]>1.e-9 || int(sigma0_[0])-sigma0_[0] <-1.e-9 || int(sigma0_[0])<1 ){ - error("In case of adaptive hills with diffusion, the sigma must be an integer which is the number of timesteps\n"); - } - } + if(adaptive_==FlexibleBin::diffusion) { + if(int(sigma0_[0])-sigma0_[0]>1.e-9 || int(sigma0_[0])-sigma0_[0] <-1.e-9 || int(sigma0_[0])<1 ) { + error("In case of adaptive hills with diffusion, the sigma must be an integer which is the number of timesteps\n"); + } + } // here evtl parse the sigma min and max values parseVector("SIGMA_MIN",sigma0min_); if(sigma0min_.size()>0 && sigma0min_.size()!=getNumberOfArguments()) { error("the number of SIGMA_MIN values be the same of the number of the arguments"); - } else if(sigma0min_.size()==0) { + } else if(sigma0min_.size()==0) { sigma0min_.resize(getNumberOfArguments()); - for(unsigned i=0;i<getNumberOfArguments();i++){sigma0min_[i]=-1.;} + for(unsigned i=0; i<getNumberOfArguments(); i++) {sigma0min_[i]=-1.;} } - + parseVector("SIGMA_MAX",sigma0max_); if(sigma0max_.size()>0 && sigma0max_.size()!=getNumberOfArguments()) { - error("the number of SIGMA_MAX values be the same of the number of the arguments"); - } else if(sigma0max_.size()==0) { + error("the number of SIGMA_MAX values be the same of the number of the arguments"); + } else if(sigma0max_.size()==0) { sigma0max_.resize(getNumberOfArguments()); - for(unsigned i=0;i<getNumberOfArguments();i++){sigma0max_[i]=-1.;} + for(unsigned i=0; i<getNumberOfArguments(); i++) {sigma0max_[i]=-1.;} } - + flexbin=new FlexibleBin(adaptive_,this,sigma0_[0],sigma0min_,sigma0max_); } // note: HEIGHT is not compulsory, since one could use the TAU keyword, see below @@ -560,7 +560,7 @@ last_step_warn_grid(0) parse("FILE",hillsfname); std::vector<double> rect_biasf_; parseVector("RECT",rect_biasf_); - if(rect_biasf_.size()>0){ + if(rect_biasf_.size()>0) { int r=0; if(comm.Get_rank()==0) r=multi_sim_comm.Get_rank(); comm.Bcast(r,0); @@ -575,32 +575,32 @@ last_step_warn_grid(0) parse("TEMP",temp); if(temp>0.0) kbt_=plumed.getAtoms().getKBoltzmann()*temp; else kbt_=plumed.getAtoms().getKbT(); - if(biasf_>=1.0){ + if(biasf_>=1.0) { if(kbt_==0.0) error("Unless the MD engine passes the temperature to plumed, with well-tempered metad you must specify it using TEMP"); welltemp_=true; } - if(dampfactor_>0.0){ + if(dampfactor_>0.0) { if(kbt_==0.0) error("Unless the MD engine passes the temperature to plumed, with damped metad you must specify it using TEMP"); } parse("TARGET",targetfilename_); if(targetfilename_.length()>0 && kbt_==0.0) error("with TARGET temperature must be specified"); double tau=0.0; parse("TAU",tau); - if(tau==0.0){ + if(tau==0.0) { if(height0_==std::numeric_limits<double>::max()) error("At least one between HEIGHT and TAU should be specified"); // if tau is not set, we compute it here from the other input parameters if(welltemp_) tau=(kbt_*(biasf_-1.0))/height0_*getTimeStep()*stride_; else if(dampfactor_>0.0) tau=(kbt_*dampfactor_)/height0_*getTimeStep()*stride_; } else { if(height0_!=std::numeric_limits<double>::max()) error("At most one between HEIGHT and TAU should be specified"); - if(welltemp_){ + if(welltemp_) { if(biasf_!=1.0) height0_=(kbt_*(biasf_-1.0))/tau*getTimeStep()*stride_; else height0_=kbt_/tau*getTimeStep()*stride_; // special case for gamma=1 } else if(dampfactor_>0.0) height0_=(kbt_*dampfactor_)/tau*getTimeStep()*stride_; else error("TAU only makes sense in well-tempered or damped metadynamics"); } - + // Grid Stuff vector<std::string> gmin(getNumberOfArguments()); parseVector("GRID_MIN",gmin); @@ -617,71 +617,71 @@ last_step_warn_grid(0) if(gmin.size()!=gmax.size()) error("GRID_MAX and GRID_MIN should be either present or absent"); if(gspacing.size()!=0 && gmin.size()==0) error("If GRID_SPACING is present also GRID_MIN should be present"); if(gbin.size()!=0 && gmin.size()==0) error("If GRID_SPACING is present also GRID_MIN should be present"); - if(gmin.size()!=0){ - if(gbin.size()==0 && gspacing.size()==0){ - if(adaptive_==FlexibleBin::none){ + if(gmin.size()!=0) { + if(gbin.size()==0 && gspacing.size()==0) { + if(adaptive_==FlexibleBin::none) { log<<" Binsize not specified, 1/5 of sigma will be be used\n"; plumed_assert(sigma0_.size()==getNumberOfArguments()); gspacing.resize(getNumberOfArguments()); - for(unsigned i=0;i<gspacing.size();i++) gspacing[i]=0.2*sigma0_[i]; + for(unsigned i=0; i<gspacing.size(); i++) gspacing[i]=0.2*sigma0_[i]; } else { // with adaptive hills and grid a sigma min must be specified - for(unsigned i=0;i<sigma0min_.size();i++) if(sigma0min_[i]<=0) error("When using Adaptive Gaussians on a grid SIGMA_MIN must be specified"); + for(unsigned i=0; i<sigma0min_.size(); i++) if(sigma0min_[i]<=0) error("When using Adaptive Gaussians on a grid SIGMA_MIN must be specified"); log<<" Binsize not specified, 1/5 of sigma_min will be be used\n"; gspacing.resize(getNumberOfArguments()); - for(unsigned i=0;i<gspacing.size();i++) gspacing[i]=0.2*sigma0min_[i]; + for(unsigned i=0; i<gspacing.size(); i++) gspacing[i]=0.2*sigma0min_[i]; } - } else if(gspacing.size()!=0 && gbin.size()==0){ + } else if(gspacing.size()!=0 && gbin.size()==0) { log<<" The number of bins will be estimated from GRID_SPACING\n"; - } else if(gspacing.size()!=0 && gbin.size()!=0){ + } else if(gspacing.size()!=0 && gbin.size()!=0) { log<<" You specified both GRID_BIN and GRID_SPACING\n"; log<<" The more conservative (highest) number of bins will be used for each variable\n"; } if(gbin.size()==0) gbin.assign(getNumberOfArguments(),1); - if(gspacing.size()!=0) for(unsigned i=0;i<getNumberOfArguments();i++){ - double a,b; - Tools::convert(gmin[i],a); - Tools::convert(gmax[i],b); - unsigned n=((b-a)/gspacing[i])+1; - if(gbin[i]<n) gbin[i]=n; - } + if(gspacing.size()!=0) for(unsigned i=0; i<getNumberOfArguments(); i++) { + double a,b; + Tools::convert(gmin[i],a); + Tools::convert(gmax[i],b); + unsigned n=((b-a)/gspacing[i])+1; + if(gbin[i]<n) gbin[i]=n; + } } bool sparsegrid=false; parseFlag("GRID_SPARSE",sparsegrid); bool nospline=false; parseFlag("GRID_NOSPLINE",nospline); bool spline=!nospline; - if(gbin.size()>0){grid_=true;} + if(gbin.size()>0) {grid_=true;} parse("GRID_WSTRIDE",wgridstride_); string gridfilename_; - parse("GRID_WFILE",gridfilename_); + parse("GRID_WFILE",gridfilename_); parseFlag("STORE_GRIDS",storeOldGrids_); - if(grid_ && gridfilename_.length()>0){ + if(grid_ && gridfilename_.length()>0) { if(wgridstride_==0 ) error("frequency with which to output grid not specified use GRID_WSTRIDE"); } - if(grid_ && wgridstride_>0){ - if(gridfilename_.length()==0) error("grid filename not specified use GRID_WFILE"); + if(grid_ && wgridstride_>0) { + if(gridfilename_.length()==0) error("grid filename not specified use GRID_WFILE"); } string gridreadfilename_; parse("GRID_RFILE",gridreadfilename_); if(!grid_&&gridfilename_.length()> 0) error("To write a grid you need first to define it!"); if(!grid_&&gridreadfilename_.length()>0) error("To read a grid you need first to define it!"); - - if(grid_){ - parseVector("REWEIGHTING_NGRID",rewf_grid_); - if(rewf_grid_.size()>0 && rewf_grid_.size()!=getNumberOfArguments()){ + + if(grid_) { + parseVector("REWEIGHTING_NGRID",rewf_grid_); + if(rewf_grid_.size()>0 && rewf_grid_.size()!=getNumberOfArguments()) { error("size mismatch for REWEIGHTING_NGRID keyword"); - } else if(rewf_grid_.size()==getNumberOfArguments()){ - for(unsigned j=0;j<getNumberOfArguments();++j){ - if( !getPntrToArgument(j)->isPeriodic() ) rewf_grid_[j] += 1; + } else if(rewf_grid_.size()==getNumberOfArguments()) { + for(unsigned j=0; j<getNumberOfArguments(); ++j) { + if( !getPntrToArgument(j)->isPeriodic() ) rewf_grid_[j] += 1; } } if(adaptive_==FlexibleBin::diffusion || adaptive_==FlexibleBin::geometry) warning("reweighting has not been proven to work with adaptive Gaussians"); rewf_ustride_=50; parse("REWEIGHTING_NHILLS",rewf_ustride_); } - if(dampfactor_>0.0){ + if(dampfactor_>0.0) { if(!grid_) error("With DAMPFACTOR you should use grids"); } @@ -716,32 +716,32 @@ last_step_warn_grid(0) log.printf(" Gaussian width "); if (adaptive_==FlexibleBin::diffusion)log.printf(" (Note: The units of sigma are in timesteps) "); if (adaptive_==FlexibleBin::geometry)log.printf(" (Note: The units of sigma are in dist units) "); - for(unsigned i=0;i<sigma0_.size();++i) log.printf(" %f",sigma0_[i]); + for(unsigned i=0; i<sigma0_.size(); ++i) log.printf(" %f",sigma0_[i]); log.printf(" Gaussian height %f\n",height0_); - log.printf(" Gaussian deposition pace %d\n",stride_); + log.printf(" Gaussian deposition pace %d\n",stride_); log.printf(" Gaussian file %s\n",hillsfname.c_str()); - if(welltemp_){ + if(welltemp_) { log.printf(" Well-Tempered Bias Factor %f\n",biasf_); log.printf(" Hills relaxation time (tau) %f\n",tau); log.printf(" KbT %f\n",kbt_); } if(doInt_) log.printf(" Upper and Lower limits boundaries for the bias are activated at %f - %f\n", lowI_, uppI_); - if(grid_){ + if(grid_) { log.printf(" Grid min"); - for(unsigned i=0;i<gmin.size();++i) log.printf(" %s",gmin[i].c_str() ); + for(unsigned i=0; i<gmin.size(); ++i) log.printf(" %s",gmin[i].c_str() ); log.printf("\n"); log.printf(" Grid max"); - for(unsigned i=0;i<gmax.size();++i) log.printf(" %s",gmax[i].c_str() ); + for(unsigned i=0; i<gmax.size(); ++i) log.printf(" %s",gmax[i].c_str() ); log.printf("\n"); log.printf(" Grid bin"); - for(unsigned i=0;i<gbin.size();++i) log.printf(" %u",gbin[i]); + for(unsigned i=0; i<gbin.size(); ++i) log.printf(" %u",gbin[i]); log.printf("\n"); - if(spline){log.printf(" Grid uses spline interpolation\n");} - if(sparsegrid){log.printf(" Grid uses sparse grid\n");} - if(wgridstride_>0){log.printf(" Grid is written on file %s with stride %d\n",gridfilename_.c_str(),wgridstride_);} + if(spline) {log.printf(" Grid uses spline interpolation\n");} + if(sparsegrid) {log.printf(" Grid uses sparse grid\n");} + if(wgridstride_>0) {log.printf(" Grid is written on file %s with stride %d\n",gridfilename_.c_str(),wgridstride_);} } - if(mw_n_>1){ + if(mw_n_>1) { if(walkers_mpi) error("MPI version of multiple walkers is not compatible with filesystem version of multiple walkers"); log.printf(" %d multiple walkers active\n",mw_n_); log.printf(" walker id %d\n",mw_id_); @@ -749,9 +749,9 @@ last_step_warn_grid(0) if(mw_dir_!="")log.printf(" directory with hills files %s\n",mw_dir_.c_str()); } else { if(walkers_mpi) { - log.printf(" Multiple walkers active using MPI communnication\n"); + log.printf(" Multiple walkers active using MPI communnication\n"); if(mw_dir_!="")log.printf(" directory with hills files %s\n",mw_dir_.c_str()); - if(comm.Get_rank()==0){ + if(comm.Get_rank()==0) { // Only root of group can communicate with other walkers mpi_nw_=multi_sim_comm.Get_size(); mpi_mw_=multi_sim_comm.Get_rank(); @@ -763,16 +763,16 @@ last_step_warn_grid(0) } } - if( rewf_grid_.size()>0 ){ + if( rewf_grid_.size()>0 ) { addComponent("rbias"); componentIsNotPeriodic("rbias"); - addComponent("rct"); componentIsNotPeriodic("rct"); + addComponent("rct"); componentIsNotPeriodic("rct"); log.printf(" the c(t) reweighting factor will be calculated every %u hills\n",rewf_ustride_); getPntrToComponent("rct")->set(reweight_factor); } addComponent("work"); componentIsNotPeriodic("work"); if(acceleration) { - if(!welltemp_) error("The calculation of the acceleration works only if Well-Tempered Metadynamics is on"); + if(!welltemp_) error("The calculation of the acceleration works only if Well-Tempered Metadynamics is on"); log.printf(" calculation on the fly of the acceleration factor"); addComponent("acc"); componentIsNotPeriodic("acc"); } @@ -781,37 +781,37 @@ last_step_warn_grid(0) dp_ = new double[getNumberOfArguments()]; // initializing and checking grid - if(grid_){ - // check for mesh and sigma size - for(unsigned i=0;i<getNumberOfArguments();i++) { - double a,b; - Tools::convert(gmin[i],a); - Tools::convert(gmax[i],b); - double mesh=(b-a)/((double)gbin[i]); - if(adaptive_==FlexibleBin::none) { - if(mesh>0.5*sigma0_[i]) log<<" WARNING: Using a METAD with a Grid Spacing larger than half of the Gaussians width can produce artifacts\n"; - } else { - if(mesh>0.5*sigma0min_[i]||sigma0min_[i]<0.) log<<" WARNING: to use a METAD with a GRID and ADAPTIVE you need to set a Grid Spacing larger than half of the Gaussians \n"; - } - } - std::string funcl=getLabel() + ".bias"; - if(!sparsegrid){BiasGrid_=new Grid(funcl,getArguments(),gmin,gmax,gbin,spline,true);} - else{BiasGrid_=new SparseGrid(funcl,getArguments(),gmin,gmax,gbin,spline,true);} - std::vector<std::string> actualmin=BiasGrid_->getMin(); - std::vector<std::string> actualmax=BiasGrid_->getMax(); - for(unsigned i=0;i<getNumberOfArguments();i++){ - if(gmin[i]!=actualmin[i]) log<<" WARNING: GRID_MIN["<<i<<"] has been adjusted to "<<actualmin[i]<<" to fit periodicity\n"; - if(gmax[i]!=actualmax[i]) log<<" WARNING: GRID_MAX["<<i<<"] has been adjusted to "<<actualmax[i]<<" to fit periodicity\n"; - } + if(grid_) { + // check for mesh and sigma size + for(unsigned i=0; i<getNumberOfArguments(); i++) { + double a,b; + Tools::convert(gmin[i],a); + Tools::convert(gmax[i],b); + double mesh=(b-a)/((double)gbin[i]); + if(adaptive_==FlexibleBin::none) { + if(mesh>0.5*sigma0_[i]) log<<" WARNING: Using a METAD with a Grid Spacing larger than half of the Gaussians width can produce artifacts\n"; + } else { + if(mesh>0.5*sigma0min_[i]||sigma0min_[i]<0.) log<<" WARNING: to use a METAD with a GRID and ADAPTIVE you need to set a Grid Spacing larger than half of the Gaussians \n"; + } + } + std::string funcl=getLabel() + ".bias"; + if(!sparsegrid) {BiasGrid_=new Grid(funcl,getArguments(),gmin,gmax,gbin,spline,true);} + else {BiasGrid_=new SparseGrid(funcl,getArguments(),gmin,gmax,gbin,spline,true);} + std::vector<std::string> actualmin=BiasGrid_->getMin(); + std::vector<std::string> actualmax=BiasGrid_->getMax(); + for(unsigned i=0; i<getNumberOfArguments(); i++) { + if(gmin[i]!=actualmin[i]) log<<" WARNING: GRID_MIN["<<i<<"] has been adjusted to "<<actualmin[i]<<" to fit periodicity\n"; + if(gmax[i]!=actualmax[i]) log<<" WARNING: GRID_MAX["<<i<<"] has been adjusted to "<<actualmax[i]<<" to fit periodicity\n"; + } } // restart from external grid bool restartedFromGrid=false; - if(gridreadfilename_.length()>0){ + if(gridreadfilename_.length()>0) { // read the grid in input, find the keys - IFile gridfile; + IFile gridfile; gridfile.link(*this); - if(gridfile.FileExist(gridreadfilename_)){ + if(gridfile.FileExist(gridreadfilename_)) { gridfile.open(gridreadfilename_); } else { error("The GRID file you want to read: " + gridreadfilename_ + ", cannot be found!"); @@ -820,7 +820,7 @@ last_step_warn_grid(0) BiasGrid_=Grid::create(funcl, getArguments(), gridfile, gmin, gmax, gbin, sparsegrid, spline, true); gridfile.close(); if(BiasGrid_->getDimension()!=getNumberOfArguments()) error("mismatch between dimensionality of input grid and number of arguments"); - for(unsigned i=0;i<getNumberOfArguments();++i){ + for(unsigned i=0; i<getNumberOfArguments(); ++i) { if( getPntrToArgument(i)->isPeriodic()!=BiasGrid_->getIsPeriodic()[i] ) error("periodicity mismatch between arguments and input bias"); double a, b; Tools::convert(gmin[i],a); @@ -828,16 +828,16 @@ last_step_warn_grid(0) double mesh=(b-a)/((double)gbin[i]); if(mesh>0.5*sigma0_[i]) log<<" WARNING: Using a METAD with a Grid Spacing larger than half of the Gaussians width can produce artifacts\n"; } - log.printf(" Restarting from %s:",gridreadfilename_.c_str()); + log.printf(" Restarting from %s:",gridreadfilename_.c_str()); if(getRestart()) restartedFromGrid=true; } // initializing and checking grid - if(grid_&&!(gridreadfilename_.length()>0)){ + if(grid_&&!(gridreadfilename_.length()>0)) { // check for adaptive and sigma_min if(sigma0min_.size()==0&&adaptive_!=FlexibleBin::none) error("When using Adaptive Gaussians on a grid SIGMA_MIN must be specified"); // check for mesh and sigma size - for(unsigned i=0;i<getNumberOfArguments();i++) { + for(unsigned i=0; i<getNumberOfArguments(); i++) { double a,b; Tools::convert(gmin[i],a); Tools::convert(gmax[i],b); @@ -845,19 +845,19 @@ last_step_warn_grid(0) if(mesh>0.5*sigma0_[i]) log<<" WARNING: Using a METAD with a Grid Spacing larger than half of the Gaussians width can produce artifacts\n"; } std::string funcl=getLabel() + ".bias"; - if(!sparsegrid){BiasGrid_=new Grid(funcl,getArguments(),gmin,gmax,gbin,spline,true);} - else{BiasGrid_=new SparseGrid(funcl,getArguments(),gmin,gmax,gbin,spline,true);} + if(!sparsegrid) {BiasGrid_=new Grid(funcl,getArguments(),gmin,gmax,gbin,spline,true);} + else {BiasGrid_=new SparseGrid(funcl,getArguments(),gmin,gmax,gbin,spline,true);} std::vector<std::string> actualmin=BiasGrid_->getMin(); std::vector<std::string> actualmax=BiasGrid_->getMax(); - for(unsigned i=0;i<getNumberOfArguments();i++){ + for(unsigned i=0; i<getNumberOfArguments(); i++) { if(gmin[i]!=actualmin[i]) log<<" WARNING: GRID_MIN["<<i<<"] has been adjusted to "<<actualmin[i]<<" to fit periodicity\n"; if(gmax[i]!=actualmax[i]) log<<" WARNING: GRID_MAX["<<i<<"] has been adjusted to "<<actualmax[i]<<" to fit periodicity\n"; } } - // creating vector of ifile* for hills reading + // creating vector of ifile* for hills reading // open all files at the beginning and read Gaussians if restarting - for(int i=0;i<mw_n_;++i){ + for(int i=0; i<mw_n_; ++i) { string fname; if(mw_dir_!="") { if(mw_n_>1) { @@ -878,13 +878,13 @@ last_step_warn_grid(0) } IFile *ifile = new IFile(); ifile->link(*this); - ifiles.push_back(ifile); + ifiles.push_back(ifile); ifilesnames.push_back(fname); - if(ifile->FileExist(fname)){ + if(ifile->FileExist(fname)) { ifile->open(fname); - if(getRestart()&&!restartedFromGrid){ - log.printf(" Restarting from %s:",ifilesnames[i].c_str()); - readGaussians(ifiles[i]); + if(getRestart()&&!restartedFromGrid) { + log.printf(" Restarting from %s:",ifilesnames[i].c_str()); + readGaussians(ifiles[i]); } ifiles[i]->reset(false); // close only the walker own hills file for later writing @@ -901,13 +901,13 @@ last_step_warn_grid(0) // (e.g. in bias exchange with a neutral replica) // see issue #168 on github if(comm.Get_rank()==0 && walkers_mpi) multi_sim_comm.Barrier(); - if(targetfilename_.length()>0){ + if(targetfilename_.length()>0) { IFile gridfile; gridfile.open(targetfilename_); std::string funcl=getLabel() + ".target"; TargetGrid_=Grid::create(funcl,getArguments(),gridfile,false,false,true); gridfile.close(); if(TargetGrid_->getDimension()!=getNumberOfArguments()) error("mismatch between dimensionality of input grid and number of arguments"); - for(unsigned i=0;i<getNumberOfArguments();++i){ + for(unsigned i=0; i<getNumberOfArguments(); ++i) { if( getPntrToArgument(i)->isPeriodic()!=TargetGrid_->getIsPeriodic()[i] ) error("periodicity mismatch between arguments and input bias"); } } @@ -916,9 +916,9 @@ last_step_warn_grid(0) if(getRestart() && rewf_grid_.size()>0 ) computeReweightingFactor(); // open grid file for writing - if(wgridstride_>0){ + if(wgridstride_>0) { gridfile_.link(*this); - if(walkers_mpi){ + if(walkers_mpi) { int r=0; if(comm.Get_rank()==0) r=multi_sim_comm.Get_rank(); comm.Bcast(r,0); @@ -931,7 +931,7 @@ last_step_warn_grid(0) // open hills file for writing hillsOfile_.link(*this); - if(walkers_mpi){ + if(walkers_mpi) { int r=0; if(comm.Get_rank()==0) r=multi_sim_comm.Get_rank(); comm.Bcast(r,0); @@ -948,14 +948,14 @@ last_step_warn_grid(0) } hillsOfile_.setHeavyFlush(); // output periodicities of variables - for(unsigned i=0;i<getNumberOfArguments();++i) hillsOfile_.setupPrintValue( getPntrToArgument(i) ); + for(unsigned i=0; i<getNumberOfArguments(); ++i) hillsOfile_.setupPrintValue( getPntrToArgument(i) ); bool concurrent=false; const ActionSet&actionSet(plumed.getActionSet()); - for(const auto & p : actionSet) if(dynamic_cast<MetaD*>(p)){ concurrent=true; break; } + for(const auto & p : actionSet) if(dynamic_cast<MetaD*>(p)) { concurrent=true; break; } if(concurrent) log<<" You are using concurrent metadynamics\n"; - if(rect_biasf_.size()>0){ - if(walkers_mpi){ + if(rect_biasf_.size()>0) { + if(walkers_mpi) { log<<" You are using RECT in its 'altruistic' implementation\n"; }{ log<<" You are using RECT\n"; @@ -964,22 +964,22 @@ last_step_warn_grid(0) log<<" Bibliography "<<plumed.cite("Laio and Parrinello, PNAS 99, 12562 (2002)"); if(welltemp_) log<<plumed.cite( - "Barducci, Bussi, and Parrinello, Phys. Rev. Lett. 100, 020603 (2008)"); + "Barducci, Bussi, and Parrinello, Phys. Rev. Lett. 100, 020603 (2008)"); if(mw_n_>1||walkers_mpi) log<<plumed.cite( - "Raiteri, Laio, Gervasio, Micheletti, and Parrinello, J. Phys. Chem. B 110, 3533 (2006)"); + "Raiteri, Laio, Gervasio, Micheletti, and Parrinello, J. Phys. Chem. B 110, 3533 (2006)"); if(adaptive_!=FlexibleBin::none) log<<plumed.cite( - "Branduardi, Bussi, and Parrinello, J. Chem. Theory Comput. 8, 2247 (2012)"); + "Branduardi, Bussi, and Parrinello, J. Chem. Theory Comput. 8, 2247 (2012)"); if(doInt_) log<<plumed.cite( - "Baftizadeh, Cossio, Pietrucci, and Laio, Curr. Phys. Chem. 2, 79 (2012)"); + "Baftizadeh, Cossio, Pietrucci, and Laio, Curr. Phys. Chem. 2, 79 (2012)"); if(acceleration) log<<plumed.cite( - "Pratyush and Parrinello, Phys. Rev. Lett. 111, 230602 (2013)"); + "Pratyush and Parrinello, Phys. Rev. Lett. 111, 230602 (2013)"); if(rewf_grid_.size()>0) log<<plumed.cite( - "Pratyush and Parrinello, J. Phys. Chem. B, 119, 736 (2015)"); + "Pratyush and Parrinello, J. Phys. Chem. B, 119, 736 (2015)"); if(concurrent || rect_biasf_.size()>0) log<<plumed.cite( - "Gil-Ley and Bussi, J. Chem. Theory Comput. 11, 1077 (2015)"); + "Gil-Ley and Bussi, J. Chem. Theory Comput. 11, 1077 (2015)"); if(rect_biasf_.size()>0 && walkers_mpi) log<<plumed.cite( - "Hosek, Toulcova, Bortolato, and Spiwok, J. Phys. Chem. B 120, 2209 (2016)"); - if(targetfilename_.length()>0){ + "Hosek, Toulcova, Bortolato, and Spiwok, J. Phys. Chem. B 120, 2209 (2016)"); + if(targetfilename_.length()>0) { log<<plumed.cite("White, Dama, and Voth, J. Chem. Theory Comput. 11, 2451 (2015)"); log<<plumed.cite("Marinelli and Faraldo-GoÌmez, Biophys. J. 108, 2779 (2015)"); log<<plumed.cite("Gil-Ley, Bottaro, and Bussi, submitted (2016)"); @@ -993,18 +993,19 @@ void MetaD::readGaussians(IFile *ifile) vector<double> center(ncv); vector<double> sigma(ncv); double height; - int nhills=0; + int nhills=0; bool multivariate=false; - + std::vector<Value> tmpvalues; - for(unsigned j=0;j<getNumberOfArguments();++j) tmpvalues.push_back( Value( this, getPntrToArgument(j)->getName(), false ) ); - - while(scanOneHill(ifile,tmpvalues,center,sigma,height,multivariate)){; + for(unsigned j=0; j<getNumberOfArguments(); ++j) tmpvalues.push_back( Value( this, getPntrToArgument(j)->getName(), false ) ); + + while(scanOneHill(ifile,tmpvalues,center,sigma,height,multivariate)) { + ; nhills++; // note that for gamma=1 we store directly -F - if(welltemp_ && biasf_>1.0){height*=(biasf_-1.0)/biasf_;} + if(welltemp_ && biasf_>1.0) {height*=(biasf_-1.0)/biasf_;} addGaussian(Gaussian(center,sigma,height,multivariate)); - } + } log.printf(" %d Gaussians read\n",nhills); } @@ -1017,18 +1018,19 @@ bool MetaD::readChunkOfGaussians(IFile *ifile, unsigned n) unsigned nhills=0; bool multivariate=false; std::vector<Value> tmpvalues; - for(unsigned j=0;j<getNumberOfArguments();++j) tmpvalues.push_back( Value( this, getPntrToArgument(j)->getName(), false ) ); - - while(scanOneHill(ifile,tmpvalues,center,sigma,height,multivariate)){; + for(unsigned j=0; j<getNumberOfArguments(); ++j) tmpvalues.push_back( Value( this, getPntrToArgument(j)->getName(), false ) ); + + while(scanOneHill(ifile,tmpvalues,center,sigma,height,multivariate)) { + ; // note that for gamma=1 we store directly -F - if(welltemp_ && biasf_>1.0) height*=(biasf_-1.0)/biasf_; + if(welltemp_ && biasf_>1.0) height*=(biasf_-1.0)/biasf_; addGaussian(Gaussian(center,sigma,height,multivariate)); - if(nhills==n){ + if(nhills==n) { log.printf(" %u Gaussians read\n",nhills); return true; } nhills++; - } + } log.printf(" %u Gaussians read\n",nhills); return false; } @@ -1037,26 +1039,26 @@ void MetaD::writeGaussian(const Gaussian& hill, OFile&file) { unsigned ncv=getNumberOfArguments(); file.printField("time",getTimeStep()*getStep()); - for(unsigned i=0;i<ncv;++i){ + for(unsigned i=0; i<ncv; ++i) { file.printField(getPntrToArgument(i),hill.center[i]); } - if(hill.multivariate){ + if(hill.multivariate) { hillsOfile_.printField("multivariate","true"); Matrix<double> mymatrix(ncv,ncv); unsigned k=0; - for(unsigned i=0;i<ncv;i++){ - for(unsigned j=i;j<ncv;j++){ + for(unsigned i=0; i<ncv; i++) { + for(unsigned j=i; j<ncv; j++) { // recompose the full inverse matrix mymatrix(i,j)=mymatrix(j,i)=hill.sigma[k]; k++; } } - // invert it + // invert it Matrix<double> invmatrix(ncv,ncv); Invert(mymatrix,invmatrix); // enforce symmetry - for(unsigned i=0;i<ncv;i++){ - for(unsigned j=i;j<ncv;j++){ + for(unsigned i=0; i<ncv; i++) { + for(unsigned j=i; j<ncv; j++) { invmatrix(i,j)=invmatrix(j,i); } } @@ -1064,20 +1066,20 @@ void MetaD::writeGaussian(const Gaussian& hill, OFile&file) // do cholesky so to have a "sigma like" number Matrix<double> lower(ncv,ncv); cholesky(invmatrix,lower); - // loop in band form - for(unsigned i=0;i<ncv;i++){ - for(unsigned j=0;j<ncv-i;j++){ + // loop in band form + for(unsigned i=0; i<ncv; i++) { + for(unsigned j=0; j<ncv-i; j++) { file.printField("sigma_"+getPntrToArgument(j+i)->getName()+"_"+getPntrToArgument(j)->getName(),lower(j+i,j)); } } } else { hillsOfile_.printField("multivariate","false"); - for(unsigned i=0;i<ncv;++i) + for(unsigned i=0; i<ncv; ++i) file.printField("sigma_"+getPntrToArgument(i)->getName(),hill.sigma[i]); } double height=hill.height; // note that for gamma=1 we store directly -F - if(welltemp_ && biasf_>1.0) height*=biasf_/(biasf_-1.0); + if(welltemp_ && biasf_>1.0) height*=biasf_/(biasf_-1.0); file.printField("height",height).printField("biasf",biasf_); if(mw_n_>1) file.printField("clock",int(std::time(0))); file.printField(); @@ -1085,36 +1087,36 @@ void MetaD::writeGaussian(const Gaussian& hill, OFile&file) void MetaD::addGaussian(const Gaussian& hill) { - if(!grid_) hills_.push_back(hill); + if(!grid_) hills_.push_back(hill); else { unsigned ncv=getNumberOfArguments(); vector<unsigned> nneighb=getGaussianSupport(hill); vector<Grid::index_t> neighbors=BiasGrid_->getNeighbors(hill.center,nneighb); vector<double> der(ncv); vector<double> xx(ncv); - if(comm.Get_size()==1){ - for(unsigned i=0;i<neighbors.size();++i){ + if(comm.Get_size()==1) { + for(unsigned i=0; i<neighbors.size(); ++i) { Grid::index_t ineigh=neighbors[i]; - for(unsigned j=0;j<ncv;++j) der[j]=0.0; + for(unsigned j=0; j<ncv; ++j) der[j]=0.0; BiasGrid_->getPoint(ineigh,xx); double bias=evaluateGaussian(xx,hill,&der[0]); BiasGrid_->addValueAndDerivatives(ineigh,bias,der); - } + } } else { unsigned stride=comm.Get_size(); unsigned rank=comm.Get_rank(); vector<double> allder(ncv*neighbors.size(),0.0); vector<double> allbias(neighbors.size(),0.0); - for(unsigned i=rank;i<neighbors.size();i+=stride){ + for(unsigned i=rank; i<neighbors.size(); i+=stride) { Grid::index_t ineigh=neighbors[i]; BiasGrid_->getPoint(ineigh,xx); allbias[i]=evaluateGaussian(xx,hill,&allder[ncv*i]); } comm.Sum(allbias); comm.Sum(allder); - for(unsigned i=0;i<neighbors.size();++i){ + for(unsigned i=0; i<neighbors.size(); ++i) { Grid::index_t ineigh=neighbors[i]; - for(unsigned j=0;j<ncv;++j){der[j]=allder[ncv*i+j];} + for(unsigned j=0; j<ncv; ++j) {der[j]=allder[ncv*i+j];} BiasGrid_->addValueAndDerivatives(ineigh,allbias[i],der); } } @@ -1124,42 +1126,42 @@ void MetaD::addGaussian(const Gaussian& hill) vector<unsigned> MetaD::getGaussianSupport(const Gaussian& hill) { vector<unsigned> nneigh; - vector<double> cutoff; + vector<double> cutoff; unsigned ncv=getNumberOfArguments(); - // traditional or flexible hill? - if(hill.multivariate){ + // traditional or flexible hill? + if(hill.multivariate) { unsigned k=0; Matrix<double> mymatrix(ncv,ncv); - for(unsigned i=0;i<ncv;i++){ - for(unsigned j=i;j<ncv;j++){ + for(unsigned i=0; i<ncv; i++) { + for(unsigned j=i; j<ncv; j++) { // recompose the full inverse matrix mymatrix(i,j)=mymatrix(j,i)=hill.sigma[k]; k++; } } - // Reinvert so to have the ellipses + // Reinvert so to have the ellipses Matrix<double> myinv(ncv,ncv); Invert(mymatrix,myinv); Matrix<double> myautovec(ncv,ncv); - vector<double> myautoval(ncv); //should I take this or their square root? + vector<double> myautoval(ncv); //should I take this or their square root? diagMat(myinv,myautoval,myautovec); double maxautoval=0.; - unsigned ind_maxautoval;ind_maxautoval=ncv; - for(unsigned i=0;i<ncv;i++){ - if(myautoval[i]>maxautoval){maxautoval=myautoval[i];ind_maxautoval=i;} - } - for(unsigned i=0;i<ncv;i++){ + unsigned ind_maxautoval; ind_maxautoval=ncv; + for(unsigned i=0; i<ncv; i++) { + if(myautoval[i]>maxautoval) {maxautoval=myautoval[i]; ind_maxautoval=i;} + } + for(unsigned i=0; i<ncv; i++) { cutoff.push_back(sqrt(2.0*DP2CUTOFF)*abs(sqrt(maxautoval)*myautovec(i,ind_maxautoval))); } } else { - for(unsigned i=0;i<ncv;++i){ + for(unsigned i=0; i<ncv; ++i) { cutoff.push_back(sqrt(2.0*DP2CUTOFF)*hill.sigma[i]); } } - if(doInt_){ - if(hill.center[0]+cutoff[0] > uppI_ || hill.center[0]-cutoff[0] < lowI_) { + if(doInt_) { + if(hill.center[0]+cutoff[0] > uppI_ || hill.center[0]-cutoff[0] < lowI_) { // in this case, we updated the entire grid to avoid problems return BiasGrid_->getNbin(); } else { @@ -1167,19 +1169,19 @@ vector<unsigned> MetaD::getGaussianSupport(const Gaussian& hill) return nneigh; } } else { - for(unsigned i=0;i<ncv;i++){ + for(unsigned i=0; i<ncv; i++) { nneigh.push_back( static_cast<unsigned>(ceil(cutoff[i]/BiasGrid_->getDx()[i])) ); } } - + return nneigh; } double MetaD::getBiasAndDerivatives(const vector<double>& cv, double* der) { double bias=0.0; - if(!grid_){ - if(hills_.size()>10000 && (getStep()-last_step_warn_grid)>10000){ + if(!grid_) { + if(hills_.size()>10000 && (getStep()-last_step_warn_grid)>10000) { std::string msg; Tools::convert(hills_.size(),msg); msg="You have accumulated "+msg+" hills, you should enable GRIDs to avoid serious performance hits"; @@ -1188,19 +1190,19 @@ double MetaD::getBiasAndDerivatives(const vector<double>& cv, double* der) } unsigned stride=comm.Get_size(); unsigned rank=comm.Get_rank(); - for(unsigned i=rank;i<hills_.size();i+=stride){ + for(unsigned i=rank; i<hills_.size(); i+=stride) { bias+=evaluateGaussian(cv,hills_[i],der); } comm.Sum(bias); if(der) comm.Sum(der,getNumberOfArguments()); - } else { - if(der){ - vector<double> vder(getNumberOfArguments()); - bias=BiasGrid_->getValueAndDerivatives(cv,vder); - for(unsigned i=0;i<getNumberOfArguments();++i) {der[i]=vder[i];} - } else { + } else { + if(der) { + vector<double> vder(getNumberOfArguments()); + bias=BiasGrid_->getValueAndDerivatives(cv,vder); + for(unsigned i=0; i<getNumberOfArguments(); ++i) {der[i]=vder[i];} + } else { bias = BiasGrid_->getValue(cv); - } + } } return bias; @@ -1208,15 +1210,15 @@ double MetaD::getBiasAndDerivatives(const vector<double>& cv, double* der) double MetaD::getGaussianNormalization( const Gaussian& hill ) { - double norm=1; + double norm=1; unsigned ncv=hill.center.size(); - if(hill.multivariate){ - // recompose the full sigma from the upper diag cholesky - unsigned k=0; + if(hill.multivariate) { + // recompose the full sigma from the upper diag cholesky + unsigned k=0; Matrix<double> mymatrix(ncv,ncv); - for(unsigned i=0;i<ncv;i++){ - for(unsigned j=i;j<ncv;j++){ + for(unsigned i=0; i<ncv; i++) { + for(unsigned j=i; j<ncv; j++) { mymatrix(i,j)=mymatrix(j,i)=hill.sigma[k]; // recompose the full inverse matrix k++; } @@ -1224,7 +1226,7 @@ double MetaD::getGaussianNormalization( const Gaussian& hill ) norm = exp( ldet ); // Not sure here if mymatrix is sigma or inverse } } else { - for(unsigned i=0;i<hill.sigma.size();++i) norm*=hill.sigma[i]; + for(unsigned i=0; i<hill.sigma.size(); ++i) norm*=hill.sigma[i]; } return norm*pow(2*pi,static_cast<double>(ncv)/2.0); @@ -1240,65 +1242,65 @@ double MetaD::evaluateGaussian(const vector<double>& cv, const Gaussian& hill, d const double *pcv=NULL; // pointer to cv double tmpcv[1]; // tmp array with cv (to be used with doInt_) if(cv.size()>0) pcv=&cv[0]; - if(doInt_){ + if(doInt_) { plumed_assert(cv.size()==1); tmpcv[0]=cv[0]; if(cv[0]<lowI_) tmpcv[0]=lowI_; if(cv[0]>uppI_) tmpcv[0]=uppI_; pcv=&(tmpcv[0]); } - if(hill.multivariate){ + if(hill.multivariate) { unsigned k=0; - unsigned ncv=cv.size(); - // recompose the full sigma from the upper diag cholesky + unsigned ncv=cv.size(); + // recompose the full sigma from the upper diag cholesky Matrix<double> mymatrix(ncv,ncv); - for(unsigned i=0;i<ncv;i++){ - for(unsigned j=i;j<ncv;j++){ - mymatrix(i,j)=mymatrix(j,i)=hill.sigma[k]; // recompose the full inverse matrix - k++; - } + for(unsigned i=0; i<ncv; i++) { + for(unsigned j=i; j<ncv; j++) { + mymatrix(i,j)=mymatrix(j,i)=hill.sigma[k]; // recompose the full inverse matrix + k++; + } } - for(unsigned i=0;i<cv.size();++i){ + for(unsigned i=0; i<cv.size(); ++i) { double dp_i=difference(i,hill.center[i],pcv[i]); dp_[i]=dp_i; - for(unsigned j=i;j<cv.size();++j){ - if(i==j){ - dp2+=dp_i*dp_i*mymatrix(i,j)*0.5; - } else { - double dp_j=difference(j,hill.center[j],pcv[j]); - dp2+=dp_i*dp_j*mymatrix(i,j); + for(unsigned j=i; j<cv.size(); ++j) { + if(i==j) { + dp2+=dp_i*dp_i*mymatrix(i,j)*0.5; + } else { + double dp_j=difference(j,hill.center[j],pcv[j]); + dp2+=dp_i*dp_j*mymatrix(i,j); } } - } - if(dp2<DP2CUTOFF){ + } + if(dp2<DP2CUTOFF) { bias=hill.height*exp(-dp2); - if(der){ - for(unsigned i=0;i<cv.size();++i){ + if(der) { + for(unsigned i=0; i<cv.size(); ++i) { double tmp=0.0; - for(unsigned j=0;j<cv.size();++j){ + for(unsigned j=0; j<cv.size(); ++j) { tmp += dp_[j]*mymatrix(i,j)*bias; } der[i]-=tmp; - } + } } } } else { - for(unsigned i=0;i<cv.size();++i){ + for(unsigned i=0; i<cv.size(); ++i) { double dp=difference(i,hill.center[i],pcv[i])*hill.invsigma[i]; dp2+=dp*dp; dp_[i]=dp; } dp2*=0.5; - if(dp2<DP2CUTOFF){ + if(dp2<DP2CUTOFF) { bias=hill.height*exp(-dp2); - if(der){ - for(unsigned i=0;i<cv.size();++i){der[i]+=-bias*dp_[i]*hill.invsigma[i];} + if(der) { + for(unsigned i=0; i<cv.size(); ++i) {der[i]+=-bias*dp_[i]*hill.invsigma[i];} } } } - if(doInt_ && der){ - if(cv[0]<lowI_ || cv[0]>uppI_) for(unsigned i=0;i<cv.size();++i) der[i]=0; + if(doInt_ && der) { + if(cv[0]<lowI_ || cv[0]>uppI_) for(unsigned i=0; i<cv.size(); ++i) der[i]=0; } return bias; @@ -1307,21 +1309,21 @@ double MetaD::evaluateGaussian(const vector<double>& cv, const Gaussian& hill, d double MetaD::getHeight(const vector<double>& cv) { double height=height0_; - if(welltemp_){ + if(welltemp_) { double vbias = getBiasAndDerivatives(cv); - if(biasf_>1.0){ + if(biasf_>1.0) { height = height0_*exp(-vbias/(kbt_*(biasf_-1.0))); } else { // notice that if gamma=1 we store directly -F height = height0_*exp(-vbias/kbt_); } - } - if(dampfactor_>0.0){ + } + if(dampfactor_>0.0) { plumed_assert(BiasGrid_); double m=BiasGrid_->getMaxValue(); height*=exp(-m/(kbt_*(dampfactor_))); } - if(TargetGrid_){ + if(TargetGrid_) { double f=TargetGrid_->getValue(cv)-TargetGrid_->getMaxValue(); height*=exp(f/kbt_); } @@ -1337,15 +1339,15 @@ void MetaD::calculate() const unsigned ncv=getNumberOfArguments(); vector<double> cv(ncv); double* der = new double[ncv]; - for(unsigned i=0;i<ncv;++i) { + for(unsigned i=0; i<ncv; ++i) { cv[i]=getArgument(i); der[i]=0.; } double ene = getBiasAndDerivatives(cv,der); // special case for gamma=1.0 - if(biasf_==1.0){ + if(biasf_==1.0) { ene=0.0; - for(unsigned i=0;i<getNumberOfArguments();++i) {der[i]=0.0;} + for(unsigned i=0; i<getNumberOfArguments(); ++i) {der[i]=0.0;} } setBias(ene); @@ -1357,54 +1359,54 @@ void MetaD::calculate() getPntrToComponent("acc")->set(mean_acc); } getPntrToComponent("work")->set(work_); - // set Forces - for(unsigned i=0;i<ncv;++i){ + // set Forces + for(unsigned i=0; i<ncv; ++i) { setOutputForce(i,-der[i]); } delete [] der; } -void MetaD::update(){ +void MetaD::update() { vector<double> cv(getNumberOfArguments()); vector<double> thissigma; bool multivariate; // adding hills criteria (could be more complex though) - bool nowAddAHill; + bool nowAddAHill; if(getStep()%stride_==0 && !isFirstStep )nowAddAHill=true; else { nowAddAHill=false; isFirstStep=false; } - for(unsigned i=0;i<cv.size();++i) cv[i] = getArgument(i); + for(unsigned i=0; i<cv.size(); ++i) cv[i] = getArgument(i); double vbias=getBiasAndDerivatives(cv); - // if you use adaptive, call the FlexibleBin - if(adaptive_!=FlexibleBin::none){ + // if you use adaptive, call the FlexibleBin + if(adaptive_!=FlexibleBin::none) { flexbin->update(nowAddAHill); multivariate=true; } else { multivariate=false; } - if(nowAddAHill){ + if(nowAddAHill) { // add a Gaussian double height=getHeight(cv); - // returns upper diagonal inverse + // returns upper diagonal inverse if(adaptive_!=FlexibleBin::none) thissigma=flexbin->getInverseMatrix(); // returns normal sigma else thissigma=sigma0_; // In case we use walkers_mpi, it is now necessary to communicate with other replicas. - if(walkers_mpi){ + if(walkers_mpi) { // Allocate arrays to store all walkers hills std::vector<double> all_cv(mpi_nw_*cv.size(),0.0); std::vector<double> all_sigma(mpi_nw_*thissigma.size(),0.0); std::vector<double> all_height(mpi_nw_,0.0); std::vector<int> all_multivariate(mpi_nw_,0); - if(comm.Get_rank()==0){ + if(comm.Get_rank()==0) { // Communicate (only root) multi_sim_comm.Allgather(cv,all_cv); multi_sim_comm.Allgather(thissigma,all_sigma); @@ -1417,12 +1419,12 @@ void MetaD::update(){ comm.Bcast(all_sigma,0); comm.Bcast(all_height,0); comm.Bcast(all_multivariate,0); - for(unsigned i=0;i<mpi_nw_;i++){ + for(unsigned i=0; i<mpi_nw_; i++) { // actually add hills one by one std::vector<double> cv_now(cv.size()); std::vector<double> sigma_now(thissigma.size()); - for(unsigned j=0;j<cv.size();j++) cv_now[j]=all_cv[i*cv.size()+j]; - for(unsigned j=0;j<thissigma.size();j++) sigma_now[j]=all_sigma[i*thissigma.size()+j]; + for(unsigned j=0; j<cv.size(); j++) cv_now[j]=all_cv[i*cv.size()+j]; + for(unsigned j=0; j<thissigma.size(); j++) sigma_now[j]=all_sigma[i*thissigma.size()+j]; // notice that if gamma=1 we store directly -F so this scaling is not necessary: Gaussian newhill=Gaussian(cv_now,sigma_now,all_height[i]*(biasf_>1.0?(biasf_-1.0)/biasf_:1.0),all_multivariate[i]); addGaussian(newhill); @@ -1438,7 +1440,7 @@ void MetaD::update(){ // this should be outside of the if block in case // mw_rstride_ is not a multiple of stride_ - if(mw_n_>1 && getStep()%mw_rstride_==0){ + if(mw_n_>1 && getStep()%mw_rstride_==0) { hillsOfile_.flush(); } @@ -1446,7 +1448,7 @@ void MetaD::update(){ work_+=vbias1-vbias; // dump grid on file - if(wgridstride_>0&&(getStep()%wgridstride_==0||getCPT())){ + if(wgridstride_>0&&(getStep()%wgridstride_==0||getCPT())) { // in case old grids are stored, a sequence of grids should appear // this call results in a repetition of the header: if(storeOldGrids_) gridfile_.clearFields(); @@ -1457,10 +1459,10 @@ void MetaD::update(){ if(walkers_mpi) { if(comm.Get_rank()==0) r=multi_sim_comm.Get_rank(); comm.Bcast(r,0); - } + } if(r==0) gridfile_.rewind(); } - BiasGrid_->writeToFile(gridfile_); + BiasGrid_->writeToFile(gridfile_); // if a single grid is stored, it is necessary to flush it, otherwise // the file might stay empty forever (when a single grid is not large enough to // trigger flushing from the operating system). @@ -1471,83 +1473,83 @@ void MetaD::update(){ } // if multiple walkers and time to read Gaussians - if(mw_n_>1 && getStep()%mw_rstride_==0){ - for(int i=0;i<mw_n_;++i){ + if(mw_n_>1 && getStep()%mw_rstride_==0) { + for(int i=0; i<mw_n_; ++i) { // don't read your own Gaussians if(i==mw_id_) continue; - // if the file is not open yet - if(!(ifiles[i]->isOpen())){ + // if the file is not open yet + if(!(ifiles[i]->isOpen())) { // check if it exists now and open it! if(ifiles[i]->FileExist(ifilesnames[i])) { ifiles[i]->open(ifilesnames[i]); ifiles[i]->reset(false); } - // otherwise read the new Gaussians + // otherwise read the new Gaussians } else { log.printf(" Reading hills from %s:",ifilesnames[i].c_str()); readGaussians(ifiles[i]); ifiles[i]->reset(false); } } - } + } if(getStep()%(stride_*rewf_ustride_)==0 && nowAddAHill && rewf_grid_.size()>0 ) computeReweightingFactor(); } -/// takes a pointer to the file and a template string with values v and gives back the next center, sigma and height -bool MetaD::scanOneHill(IFile *ifile, vector<Value> &tmpvalues, vector<double> ¢er, vector<double> &sigma, double &height , bool &multivariate) +/// takes a pointer to the file and a template string with values v and gives back the next center, sigma and height +bool MetaD::scanOneHill(IFile *ifile, vector<Value> &tmpvalues, vector<double> ¢er, vector<double> &sigma, double &height, bool &multivariate) { double dummy; multivariate=false; - if(ifile->scanField("time",dummy)){ + if(ifile->scanField("time",dummy)) { unsigned ncv; ncv=tmpvalues.size(); - for(unsigned i=0;i<ncv;++i){ + for(unsigned i=0; i<ncv; ++i) { ifile->scanField( &tmpvalues[i] ); - if( tmpvalues[i].isPeriodic() && ! getPntrToArgument(i)->isPeriodic() ){ + if( tmpvalues[i].isPeriodic() && ! getPntrToArgument(i)->isPeriodic() ) { error("in hills file periodicity for variable " + tmpvalues[i].getName() + " does not match periodicity in input"); - } else if( tmpvalues[i].isPeriodic() ){ + } else if( tmpvalues[i].isPeriodic() ) { std::string imin, imax; tmpvalues[i].getDomain( imin, imax ); std::string rmin, rmax; getPntrToArgument(i)->getDomain( rmin, rmax ); - if( imin!=rmin || imax!=rmax ){ + if( imin!=rmin || imax!=rmax ) { error("in hills file periodicity for variable " + tmpvalues[i].getName() + " does not match periodicity in input"); } } center[i]=tmpvalues[i].get(); } - // scan for multivariate label: record the actual file position so to eventually rewind + // scan for multivariate label: record the actual file position so to eventually rewind std::string sss; ifile->scanField("multivariate",sss); if(sss=="true") multivariate=true; else if(sss=="false") multivariate=false; else plumed_merror("cannot parse multivariate = "+ sss); - if(multivariate){ + if(multivariate) { sigma.resize(ncv*(ncv+1)/2); Matrix<double> upper(ncv,ncv); Matrix<double> lower(ncv,ncv); - for(unsigned i=0;i<ncv;i++){ - for(unsigned j=0;j<ncv-i;j++){ + for(unsigned i=0; i<ncv; i++) { + for(unsigned j=0; j<ncv-i; j++) { ifile->scanField("sigma_"+getPntrToArgument(j+i)->getName()+"_"+getPntrToArgument(j)->getName(),lower(j+i,j)); upper(j,j+i)=lower(j+i,j); } } - Matrix<double> mymult(ncv,ncv); - Matrix<double> invmatrix(ncv,ncv); - mult(lower,upper,mymult); + Matrix<double> mymult(ncv,ncv); + Matrix<double> invmatrix(ncv,ncv); + mult(lower,upper,mymult); // now invert and get the sigmas Invert(mymult,invmatrix); - // put the sigmas in the usual order: upper diagonal (this time in normal form and not in band form) + // put the sigmas in the usual order: upper diagonal (this time in normal form and not in band form) unsigned k=0; - for(unsigned i=0;i<ncv;i++){ - for(unsigned j=i;j<ncv;j++){ + for(unsigned i=0; i<ncv; i++) { + for(unsigned j=i; j<ncv; j++) { sigma[k]=invmatrix(i,j); k++; } } } else { - for(unsigned i=0;i<ncv;++i){ + for(unsigned i=0; i<ncv; ++i) { ifile->scanField("sigma_"+getPntrToArgument(i)->getName(),sigma[i]); } } - + ifile->scanField("height",height); ifile->scanField("biasf",dummy); if(ifile->FieldExist("clock")) ifile->scanField("clock",dummy); @@ -1555,8 +1557,8 @@ bool MetaD::scanOneHill(IFile *ifile, vector<Value> &tmpvalues, vector<double> if(ifile->FieldExist("upper_int")) ifile->scanField("upper_int",dummy); ifile->scanField(); return true; - } else { - return false; + } else { + return false; } } @@ -1564,36 +1566,36 @@ void MetaD::computeReweightingFactor() { if( !welltemp_ ) error("cannot compute the c(t) reweighting factors for non well-tempered metadynamics"); - if(biasf_==1.0){ + if(biasf_==1.0) { // in this case we have no bias, so reweight factor is 1.0 - getPntrToComponent("rct")->set(1.0); - return; + getPntrToComponent("rct")->set(1.0); + return; } // Recover the minimum values for the grid unsigned ncv=getNumberOfArguments(); unsigned ntotgrid=1; - std::vector<double> dmin( ncv ),dmax( ncv ), grid_spacing( ncv ), vals( ncv ); - for(unsigned j=0;j<ncv;++j){ + std::vector<double> dmin( ncv ),dmax( ncv ), grid_spacing( ncv ), vals( ncv ); + for(unsigned j=0; j<ncv; ++j) { Tools::convert( BiasGrid_->getMin()[j], dmin[j] ); Tools::convert( BiasGrid_->getMax()[j], dmax[j] ); grid_spacing[j] = ( dmax[j] - dmin[j] ) / static_cast<double>( rewf_grid_[j] ); - if( !getPntrToArgument(j)->isPeriodic() ) dmax[j] += grid_spacing[j]; + if( !getPntrToArgument(j)->isPeriodic() ) dmax[j] += grid_spacing[j]; ntotgrid *= rewf_grid_[j]; } - + // Now sum over whole grid reweight_factor=0.0; double* der=new double[ncv]; std::vector<unsigned> t_index( ncv ); double sum1=0.0; double sum2=0.0; double afactor = biasf_ / (kbt_*(biasf_-1.0)); double afactor2 = 1.0 / (kbt_*(biasf_-1.0)); - unsigned rank=comm.Get_rank(), stride=comm.Get_size(); - for(unsigned i=rank;i<ntotgrid;i+=stride){ + unsigned rank=comm.Get_rank(), stride=comm.Get_size(); + for(unsigned i=rank; i<ntotgrid; i+=stride) { t_index[0]=(i%rewf_grid_[0]); unsigned kk=i; - for(unsigned j=1;j<ncv-1;++j){ kk=(kk-t_index[j-1])/rewf_grid_[i-1]; t_index[j]=(kk%rewf_grid_[i]); } + for(unsigned j=1; j<ncv-1; ++j) { kk=(kk-t_index[j-1])/rewf_grid_[i-1]; t_index[j]=(kk%rewf_grid_[i]); } if( ncv>=2 ) t_index[ncv-1]=((kk-t_index[ncv-1])/rewf_grid_[ncv-2]); - - for(unsigned j=0;j<ncv;++j) vals[j]=dmin[j] + t_index[j]*grid_spacing[j]; + + for(unsigned j=0; j<ncv; ++j) vals[j]=dmin[j] + t_index[j]*grid_spacing[j]; double currentb=getBiasAndDerivatives(vals,der); sum1 += exp( afactor*currentb ); diff --git a/src/bias/Metainference.cpp b/src/bias/Metainference.cpp index 910dc5953..e4d3e8b94 100644 --- a/src/bias/Metainference.cpp +++ b/src/bias/Metainference.cpp @@ -29,8 +29,8 @@ using namespace std; -namespace PLMD{ -namespace bias{ +namespace PLMD { +namespace bias { //+PLUMEDOC BIAS METAINFERENCE /* @@ -46,9 +46,9 @@ point or a single long-tailed gaussian common to all the data points. As from Metainference theory there are two sigma values: SIGMA_MEAN represent the error of calculating an average quanity using a finite set of replica and should be set as small as possible following the guidelines for replica-averaged simulations -in the framework of the Maximum Entropy Principle. -SIGMA_BIAS is an uncertainty parameter, sampled by a MC algorithm in the bounded interval -defined by SIGMA_MIN and SIGMA_MAX. The initial value is set at SIGMA0. The MC move is a +in the framework of the Maximum Entropy Principle. +SIGMA_BIAS is an uncertainty parameter, sampled by a MC algorithm in the bounded interval +defined by SIGMA_MIN and SIGMA_MAX. The initial value is set at SIGMA0. The MC move is a random displacement of maximum value equal to DSIGMA. \par Examples @@ -75,14 +75,14 @@ METAINFERENCE ... ARG=ardc.* NOISETYPE=MGAUSS PARAMETERS=1.9190,2.9190,3.9190,4.9190 -SCALEDATA SCALE0=1 SCALE_MIN=0.00001 SCALE_MAX=3 DSCALE=0.00 -SIGMA0=0.01 SIGMA_MIN=0.00001 SIGMA_MAX=3 DSIGMA=0.00 +SCALEDATA SCALE0=1 SCALE_MIN=0.00001 SCALE_MAX=3 DSCALE=0.00 +SIGMA0=0.01 SIGMA_MIN=0.00001 SIGMA_MAX=3 DSIGMA=0.00 SIGMA_MEAN=0.001 TEMP=300 LABEL=spe -... METAINFERENCE +... METAINFERENCE -PRINT ARG=spe.bias FILE=BIAS STRIDE=1 +PRINT ARG=spe.bias FILE=BIAS STRIDE=1 \endverbatim in the following example instead of using one uncertainty parameter per data point we use @@ -93,12 +93,12 @@ METAINFERENCE ... ARG=ardc.* NOISETYPE=OUTLIERS PARAMETERS=1.9190,2.9190,3.9190,4.9190 -SCALEDATA SCALE0=1 SCALE_MIN=0.00001 SCALE_MAX=3 DSCALE=0.00 -SIGMA0=0.01 SIGMA_MIN=0.00001 SIGMA_MAX=3 DSIGMA=0.00 +SCALEDATA SCALE0=1 SCALE_MIN=0.00001 SCALE_MAX=3 DSCALE=0.00 +SIGMA0=0.01 SIGMA_MIN=0.00001 SIGMA_MAX=3 DSIGMA=0.00 SIGMA_MEAN=0.001 TEMP=300 LABEL=spe -... METAINFERENCE +... METAINFERENCE \endverbatim (See also \ref RDC and \ref ENSEMBLE). @@ -150,7 +150,7 @@ class Metainference : public Bias void doMonteCarlo(); double getEnergyForceSPE(); double getEnergyForceGJE(); - + public: explicit Metainference(const ActionOptions&); void calculate(); @@ -160,13 +160,13 @@ public: PLUMED_REGISTER_ACTION(Metainference,"METAINFERENCE") -void Metainference::registerKeywords(Keywords& keys){ +void Metainference::registerKeywords(Keywords& keys) { Bias::registerKeywords(keys); keys.use("ARG"); - keys.add("optional","PARARG","reference values for the experimental data, these can be provided as arguments without derivatives"); + keys.add("optional","PARARG","reference values for the experimental data, these can be provided as arguments without derivatives"); keys.add("optional","PARAMETERS","reference values for the experimental data"); keys.add("compulsory","NOISETYPE","functional form of the noise (GAUSS,MGAUSS,OUTLIERS)"); - keys.addFlag("SCALEDATA",false,"Set to TRUE if you want to sample a scaling factor common to all values and replicas"); + keys.addFlag("SCALEDATA",false,"Set to TRUE if you want to sample a scaling factor common to all values and replicas"); keys.add("compulsory","SCALE0","initial value of the uncertainty parameter"); keys.add("compulsory","SCALE_MIN","minimum value of the uncertainty parameter"); keys.add("compulsory","SCALE_MAX","maximum value of the uncertainty parameter"); @@ -186,15 +186,15 @@ void Metainference::registerKeywords(Keywords& keys){ } Metainference::Metainference(const ActionOptions&ao): -PLUMED_BIAS_INIT(ao), -sqrt2_div_pi(0.45015815807855), -sqrt2_pi(2.50662827463100050240), -doscale_(false), -ndata_(getNumberOfArguments()), -MCsteps_(1), -MCstride_(1), -MCaccept_(0), -MCfirst_(-1) + PLUMED_BIAS_INIT(ao), + sqrt2_div_pi(0.45015815807855), + sqrt2_pi(2.50662827463100050240), + doscale_(false), + ndata_(getNumberOfArguments()), + MCsteps_(1), + MCstride_(1), + MCaccept_(0), + MCfirst_(-1) { parseVector("PARAMETERS",parameters); if(parameters.size()!=static_cast<unsigned>(getNumberOfArguments())&&!parameters.empty()) @@ -206,21 +206,21 @@ MCfirst_(-1) if(!arg2.empty()) { if(parameters.size()>0) error("It is not possible to use PARARG and PARAMETERS together"); if(arg2.size()!=getNumberOfArguments()) error("Size of PARARG array should be the same as number for arguments in ARG"); - for(unsigned i=0;i<arg2.size();i++){ - parameters.push_back(arg2[i]->get()); + for(unsigned i=0; i<arg2.size(); i++) { + parameters.push_back(arg2[i]->get()); if(arg2[i]->hasDerivatives()==true) error("PARARG can only accept arguments without derivatives"); } } - if(parameters.size()!=getNumberOfArguments()) + if(parameters.size()!=getNumberOfArguments()) error("PARARG or PARAMETERS arrays should include the same number of elements as the arguments in ARG"); string stringa_noise; parse("NOISETYPE",stringa_noise); - if(stringa_noise=="GAUSS") noise_type_ = GAUSS; + if(stringa_noise=="GAUSS") noise_type_ = GAUSS; else if(stringa_noise=="MGAUSS") noise_type_ = MGAUSS; else if(stringa_noise=="OUTLIERS") noise_type_ = OUTLIERS; - else error("Unkwnow noise type"); + else error("Unkwnow noise type"); parseFlag("SCALEDATA", doscale_); if(doscale_) { @@ -243,7 +243,7 @@ MCfirst_(-1) sigma_.resize(getNumberOfArguments(),readsigma[0]); } else { error("SIGMA0 can accept either one single value or as many values as the number of arguments (with NOISETYPE=MGAUSS)"); - } + } } else sigma_.resize(1, readsigma[0]); parse("SIGMA_MIN",sigma_min_); @@ -279,15 +279,15 @@ MCfirst_(-1) MCstride_ *= getStride(); switch(noise_type_) { - case GAUSS: - log.printf(" with gaussian noise and a single noise parameter for all the data\n"); - break; - case MGAUSS: - log.printf(" with gaussian noise and a noise parameter for each data point\n"); - break; - case OUTLIERS: - log.printf(" with long tailed gaussian noise and a single noise parameter for all the data\n"); - break; + case GAUSS: + log.printf(" with gaussian noise and a single noise parameter for all the data\n"); + break; + case MGAUSS: + log.printf(" with gaussian noise and a noise parameter for each data point\n"); + break; + case OUTLIERS: + log.printf(" with long tailed gaussian noise and a single noise parameter for all the data\n"); + break; } if(doscale_) { @@ -301,7 +301,7 @@ MCfirst_(-1) if(readsigma.size()==1) log.printf(" initial data uncertainty %f\n",sigma_[0]); else { log.printf(" initial data uncertainties"); - for(unsigned i=0;i<sigma_.size();++i) log.printf(" %f", sigma_[i]); + for(unsigned i=0; i<sigma_.size(); ++i) log.printf(" %f", sigma_[i]); log.printf("\n"); } log.printf(" minimum data uncertainty %f\n",sigma_min_); @@ -314,8 +314,8 @@ MCfirst_(-1) log.printf(" MC steps %u\n",MCsteps_); log.printf(" MC stride %u\n",MCstride_); - if(doscale_) { - addComponent("scale"); + if(doscale_) { + addComponent("scale"); componentIsNotPeriodic("scale"); valueScale=getPntrToComponent("scale"); } @@ -324,7 +324,7 @@ MCfirst_(-1) valueAccept=getPntrToComponent("accept"); if(noise_type_==MGAUSS) { - for(unsigned i=0;i<sigma_.size();++i){ + for(unsigned i=0; i<sigma_.size(); ++i) { std::string num; Tools::convert(i,num); addComponent("sigma_"+num); componentIsNotPeriodic("sigma_"+num); valueSigma.push_back(getPntrToComponent("sigma_"+num)); @@ -336,21 +336,21 @@ MCfirst_(-1) // initialize random seed unsigned iseed; if(comm.Get_rank()==0) iseed = time(NULL)+replica_; - else iseed = 0; + else iseed = 0; comm.Sum(&iseed, 1); srand(iseed); log<<" Bibliography "<<plumed.cite("Bonomi, Camilloni, Cavalli, Vendruscolo, Sci. Adv. 2, e150117 (2016)"); } -double Metainference::getEnergySPE(const vector<double> &sigma, const double scale){ +double Metainference::getEnergySPE(const vector<double> &sigma, const double scale) { // calculate effective sigma const double smean2 = sigma_mean_*sigma_mean_; const double s = sqrt( sigma[0]*sigma[0] + smean2 ); // cycle on arguments double ene = 0.0; - for(unsigned i=0;i<getNumberOfArguments();++i){ - const double dev = scale*getArgument(i)-parameters[i]; + for(unsigned i=0; i<getNumberOfArguments(); ++i) { + const double dev = scale*getArgument(i)-parameters[i]; // argument const double a2 = 0.5*dev*dev + s*s; // increment energy @@ -361,18 +361,18 @@ double Metainference::getEnergySPE(const vector<double> &sigma, const double sca return kbt_ * ene; } -double Metainference::getEnergyGJE(const vector<double> &sigma, const double scale){ +double Metainference::getEnergyGJE(const vector<double> &sigma, const double scale) { // cycle on arguments double ene = 0.0; const double smean2 = sigma_mean_*sigma_mean_; - double ss = sigma[0]*sigma[0] + smean2; - for(unsigned i=0;i<getNumberOfArguments();++i){ - if(noise_type_==MGAUSS){ + double ss = sigma[0]*sigma[0] + smean2; + for(unsigned i=0; i<getNumberOfArguments(); ++i) { + if(noise_type_==MGAUSS) { ss = sigma[i]*sigma[i] + smean2; // add Jeffrey's prior - one per sigma ene += 0.5*std::log(ss); } - const double dev = scale*getArgument(i)-parameters[i]; + const double dev = scale*getArgument(i)-parameters[i]; ene += 0.5*dev*dev/ss + 0.5*std::log(ss*sqrt2_pi); } // add Jeffrey's prior in case one sigma for all data points @@ -380,21 +380,21 @@ double Metainference::getEnergyGJE(const vector<double> &sigma, const double sca return kbt_ * ene; } -void Metainference::doMonteCarlo(){ +void Metainference::doMonteCarlo() { double old_energy; switch(noise_type_) { - case GAUSS: - case MGAUSS: - old_energy = getEnergyGJE(sigma_,scale_); - break; - case OUTLIERS: - old_energy = getEnergySPE(sigma_,scale_); - break; + case GAUSS: + case MGAUSS: + old_energy = getEnergyGJE(sigma_,scale_); + break; + case OUTLIERS: + old_energy = getEnergySPE(sigma_,scale_); + break; } - - // cycle on MC steps - for(unsigned i=0;i<MCsteps_;++i){ - + + // cycle on MC steps + for(unsigned i=0; i<MCsteps_; ++i) { + // propose move for scale double new_scale = scale_; if(doscale_) { @@ -402,54 +402,54 @@ void Metainference::doMonteCarlo(){ const double ds1 = -Dscale_ + r1 * 2.0 * Dscale_; new_scale += ds1; // check boundaries - if(new_scale > scale_max_){new_scale = 2.0 * scale_max_ - new_scale;} - if(new_scale < scale_min_){new_scale = 2.0 * scale_min_ - new_scale;} + if(new_scale > scale_max_) {new_scale = 2.0 * scale_max_ - new_scale;} + if(new_scale < scale_min_) {new_scale = 2.0 * scale_min_ - new_scale;} // the scaling factor should be the same for all the replicas if(comm.Get_rank()==0) multi_sim_comm.Bcast(new_scale,0); comm.Bcast(new_scale,0); } - + // propose move for sigma vector<double> new_sigma(sigma_.size()); - for(unsigned j=0;j<sigma_.size();j++) { + for(unsigned j=0; j<sigma_.size(); j++) { const double r2 = static_cast<double>(rand()) / RAND_MAX; const double ds2 = -Dsigma_ + r2 * 2.0 * Dsigma_; new_sigma[j] = sigma_[j] + ds2; // check boundaries - if(new_sigma[j] > sigma_max_){new_sigma[j] = 2.0 * sigma_max_ - new_sigma[j];} - if(new_sigma[j] < sigma_min_){new_sigma[j] = 2.0 * sigma_min_ - new_sigma[j];} + if(new_sigma[j] > sigma_max_) {new_sigma[j] = 2.0 * sigma_max_ - new_sigma[j];} + if(new_sigma[j] < sigma_min_) {new_sigma[j] = 2.0 * sigma_min_ - new_sigma[j];} } - + // calculate new energy double new_energy=0; switch(noise_type_) { - case GAUSS: - case MGAUSS: - new_energy = getEnergyGJE(new_sigma,new_scale); - break; - case OUTLIERS: - new_energy = getEnergySPE(new_sigma,new_scale); - break; + case GAUSS: + case MGAUSS: + new_energy = getEnergyGJE(new_sigma,new_scale); + break; + case OUTLIERS: + new_energy = getEnergySPE(new_sigma,new_scale); + break; } // accept or reject const double delta = ( new_energy - old_energy ) / kbt_; // if delta is negative always accept move - if( delta <= 0.0 ){ + if( delta <= 0.0 ) { old_energy = new_energy; scale_ = new_scale; sigma_ = new_sigma; MCaccept_++; - // otherwise extract random number + // otherwise extract random number } else { const double s = static_cast<double>(rand()) / RAND_MAX; - if( s < exp(-delta) ){ + if( s < exp(-delta) ) { old_energy = new_energy; scale_ = new_scale; sigma_ = new_sigma; MCaccept_++; } } - + if(doscale_) { // the scaling factor should be the same for all the replicas if(comm.Get_rank()==0) multi_sim_comm.Bcast(scale_,0); @@ -466,26 +466,26 @@ double Metainference::getEnergyForceSPE() double ene = 0.0; const unsigned narg=getNumberOfArguments(); - const double smean2 = sigma_mean_*sigma_mean_; + const double smean2 = sigma_mean_*sigma_mean_; const double s = sqrt( sigma_[0]*sigma_[0] + smean2 ); vector<double> f(narg,0); - - if(comm.Get_rank()==0){ - for(unsigned i=0;i<narg;++i){ - const double dev = scale_*getArgument(i)-parameters[i]; - const double a2 = 0.5*dev*dev + s*s; - const double t = exp(-a2/smean2); - const double dt = 1./t; - const double it = 1./(1.-t); - const double dit = 1./(1.-dt); - ene += std::log(2.*a2*it); - f[i] = -scale_*dev*(dit/smean2 + 1./a2); - } - // collect contribution to forces and energy from other replicas - multi_sim_comm.Sum(&f[0],narg); - multi_sim_comm.Sum(&ene,1); - // add normalizations and priors of local replica - ene += std::log(s) - static_cast<double>(ndata_)*std::log(sqrt2_div_pi*s); + + if(comm.Get_rank()==0) { + for(unsigned i=0; i<narg; ++i) { + const double dev = scale_*getArgument(i)-parameters[i]; + const double a2 = 0.5*dev*dev + s*s; + const double t = exp(-a2/smean2); + const double dt = 1./t; + const double it = 1./(1.-t); + const double dit = 1./(1.-dt); + ene += std::log(2.*a2*it); + f[i] = -scale_*dev*(dit/smean2 + 1./a2); + } + // collect contribution to forces and energy from other replicas + multi_sim_comm.Sum(&f[0],narg); + multi_sim_comm.Sum(&ene,1); + // add normalizations and priors of local replica + ene += std::log(s) - static_cast<double>(ndata_)*std::log(sqrt2_div_pi*s); } // intra-replica summation comm.Sum(&f[0],narg); @@ -504,19 +504,19 @@ double Metainference::getEnergyForceGJE() vector<double> inv_s2(ssize, 0.); const double smean2 = sigma_mean_*sigma_mean_; - for(unsigned i=0;i<ssize; ++i) { + for(unsigned i=0; i<ssize; ++i) { ss[i] = sigma_[i]*sigma_[i] + smean2; if(comm.Get_rank()==0) inv_s2[i] = 1.0/ss[i]; } - if(comm.Get_rank()==0) multi_sim_comm.Sum(&inv_s2[0],ssize); - comm.Sum(&inv_s2[0],ssize); - + if(comm.Get_rank()==0) multi_sim_comm.Sum(&inv_s2[0],ssize); + comm.Sum(&inv_s2[0],ssize); + const unsigned narg=getNumberOfArguments(); - for(unsigned i=0;i<narg;++i){ - const double dev = scale_*getArgument(i)-parameters[i]; + for(unsigned i=0; i<narg; ++i) { + const double dev = scale_*getArgument(i)-parameters[i]; unsigned sel_sigma=0; - if(noise_type_==MGAUSS){ + if(noise_type_==MGAUSS) { sel_sigma=i; // add Jeffrey's prior - one per sigma ene += 0.5*std::log(ss[sel_sigma]); @@ -529,7 +529,7 @@ double Metainference::getEnergyForceGJE() return ene; } -void Metainference::calculate(){ +void Metainference::calculate() { /* MONTE CARLO */ const long int step = getStep(); if(step%MCstride_==0&&!getExchangeStep()) doMonteCarlo(); @@ -540,15 +540,15 @@ void Metainference::calculate(){ valueAccept->set(accept); // calculate bias and forces - double ene = 0; + double ene = 0; switch(noise_type_) { - case GAUSS: - case MGAUSS: - ene = getEnergyForceGJE(); - break; - case OUTLIERS: - ene = getEnergyForceSPE(); - break; + case GAUSS: + case MGAUSS: + ene = getEnergyForceGJE(); + break; + case OUTLIERS: + ene = getEnergyForceSPE(); + break; } // set value of the bias setBias(kbt_*ene); diff --git a/src/bias/MovingRestraint.cpp b/src/bias/MovingRestraint.cpp index 02c08fb4e..13cafce97 100644 --- a/src/bias/MovingRestraint.cpp +++ b/src/bias/MovingRestraint.cpp @@ -26,8 +26,8 @@ using namespace std; -namespace PLMD{ -namespace bias{ +namespace PLMD { +namespace bias { //+PLUMEDOC BIAS MOVINGRESTRAINT /* @@ -39,7 +39,7 @@ and Jarzynski sampling \cite jarzynski. The harmonic restraint on your system is given by: \f[ -V(\vec{s},t) = \frac{1}{2} \kappa(t) ( \vec{s} - \vec{s}_0(t) )^2 +V(\vec{s},t) = \frac{1}{2} \kappa(t) ( \vec{s} - \vec{s}_0(t) )^2 \f] The time dependence of \f$\kappa\f$ and \f$\vec{s}_0\f$ are specified by a list of @@ -47,7 +47,7 @@ STEP, KAPPA and AT keywords. These keywords tell plumed what values \f$\kappa\f should have at the time specified by the corresponding STEP keyword. Inbetween these times the values of \f$\kappa\f$ and \f$\vec{s}_0\f$ are linearly interpolated. -Additional material and examples can be also found in the tutorial \ref belfast-5 +Additional material and examples can be also found in the tutorial \ref belfast-5 \par Examples The following input is dragging the distance between atoms 2 and 4 @@ -71,7 +71,7 @@ static. DISTANCE ATOMS=1,5 LABEL=d1 DISTANCE ATOMS=2,4 LABEL=d2 MOVINGRESTRAINT ... - ARG=d1,d2 + ARG=d1,d2 STEP0=0 AT0=1.0,1.5 KAPPA0=0.0,0.0 STEP1=1000 AT1=1.0,1.5 KAPPA1=1.0,1.0 ... MOVINGRESTRAINT @@ -88,9 +88,9 @@ MOVINGRESTRAINT ... ... MOVINGRESTRAINT \endverbatim -By default the Action is issuing some values which are +By default the Action is issuing some values which are the work on each degree of freedom, the center of the harmonic potential, -the total bias deposited +the total bias deposited (See also \ref DISTANCE). @@ -100,7 +100,7 @@ the total bias deposited //+ENDPLUMEDOC -class MovingRestraint : public Bias{ +class MovingRestraint : public Bias { std::vector<std::vector<double> > at; std::vector<std::vector<double> > kappa; std::vector<long int> step; @@ -119,54 +119,54 @@ public: PLUMED_REGISTER_ACTION(MovingRestraint,"MOVINGRESTRAINT") -void MovingRestraint::registerKeywords( Keywords& keys ){ +void MovingRestraint::registerKeywords( Keywords& keys ) { Bias::registerKeywords(keys); keys.use("ARG"); keys.add("compulsory","VERSE","B","Tells plumed whether the restraint is only acting for CV larger (U) or smaller (L) than " - "the restraint or whether it is acting on both sides (B)"); + "the restraint or whether it is acting on both sides (B)"); keys.add("numbered","STEP","This keyword appears multiple times as STEPx with x=0,1,2,...,n. Each value given represents " - "the MD step at which the restraint parameters take the values KAPPAx and ATx."); + "the MD step at which the restraint parameters take the values KAPPAx and ATx."); keys.reset_style("STEP","compulsory"); keys.add("numbered","AT","ATx is equal to the position of the restraint at time STEPx. For intermediate times this parameter " - "is linearly interpolated. If no ATx is specified for STEPx then the values of AT are kept constant " - "during the interval of time between STEPx-1 and STEPx."); - keys.reset_style("AT","compulsory"); + "is linearly interpolated. If no ATx is specified for STEPx then the values of AT are kept constant " + "during the interval of time between STEPx-1 and STEPx."); + keys.reset_style("AT","compulsory"); keys.add("numbered","KAPPA","KAPPAx is equal to the value of the force constants at time STEPx. For intermediate times this " - "parameter is linearly interpolated. If no KAPPAx is specified for STEPx then the values of KAPPAx " - "are kept constant during the interval of time between STEPx-1 and STEPx."); + "parameter is linearly interpolated. If no KAPPAx is specified for STEPx then the values of KAPPAx " + "are kept constant during the interval of time between STEPx-1 and STEPx."); keys.reset_style("KAPPA","compulsory"); keys.addOutputComponent("work","default","the total work performed changing this restraint"); keys.addOutputComponent("force2","default","the instantaneous value of the squared force due to this bias potential"); keys.addOutputComponent("_cntr","default","one or multiple instances of this quantity will be refereceable elsewhere in the input file. " - "these quantities will named with the arguments of the bias followed by " - "the character string _cntr. These quantities give the instantaneous position " - "of the center of the harmonic potential."); + "these quantities will named with the arguments of the bias followed by " + "the character string _cntr. These quantities give the instantaneous position " + "of the center of the harmonic potential."); keys.addOutputComponent("_work","default","one or multiple instances of this quantity will be refereceable elsewhere in the input file. " - "These quantities will named with the arguments of the bias followed by " - "the character string _work. These quantities tell the user how much work has " - "been done by the potential in dragging the system along the various colvar axis."); + "These quantities will named with the arguments of the bias followed by " + "the character string _work. These quantities tell the user how much work has " + "been done by the potential in dragging the system along the various colvar axis."); keys.addOutputComponent("_kappa","default","one or multiple instances of this quantity will be refereceable elsewhere in the input file. " - "These quantities will named with the arguments of the bias followed by " - "the character string _kappa. These quantities tell the user the time dependent value of kappa."); + "These quantities will named with the arguments of the bias followed by " + "the character string _kappa. These quantities tell the user the time dependent value of kappa."); } MovingRestraint::MovingRestraint(const ActionOptions&ao): -PLUMED_BIAS_INIT(ao), -verse(getNumberOfArguments()) + PLUMED_BIAS_INIT(ao), + verse(getNumberOfArguments()) { parseVector("VERSE",verse); vector<long int> ss(1); ss[0]=-1; std::vector<double> kk( getNumberOfArguments() ), aa( getNumberOfArguments() ); - for(int i=0;;i++){ - // Read in step + for(int i=0;; i++) { + // Read in step if( !parseNumberedVector("STEP",i,ss) ) break; - for(unsigned j=0;j<step.size();j++){ - if(ss[0]<step[j]) error("in moving restraint step number must always increase"); + for(unsigned j=0; j<step.size(); j++) { + if(ss[0]<step[j]) error("in moving restraint step number must always increase"); } step.push_back(ss[0]); // Try to read kappa - if( !parseNumberedVector("KAPPA",i,kk) ) kk=kappa[i-1]; + if( !parseNumberedVector("KAPPA",i,kk) ) kk=kappa[i-1]; kappa.push_back(kk); // Now read AT @@ -175,13 +175,13 @@ verse(getNumberOfArguments()) } checkRead(); - for(unsigned i=0;i<step.size();i++){ + for(unsigned i=0; i<step.size(); i++) { log.printf(" step%u %ld\n",i,step[i]); log.printf(" at"); - for(unsigned j=0;j<at[i].size();j++) log.printf(" %f",at[i][j]); + for(unsigned j=0; j<at[i].size(); j++) log.printf(" %f",at[i][j]); log.printf("\n"); log.printf(" with force constant"); - for(unsigned j=0;j<kappa[i].size();j++) log.printf(" %f",kappa[i][j]); + for(unsigned j=0; j<kappa[i].size(); j++) log.printf(" %f",kappa[i][j]); log.printf("\n"); }; @@ -190,14 +190,14 @@ verse(getNumberOfArguments()) // add the centers of the restraint as additional components that can be retrieved (useful for debug) std::string comp; - for(unsigned i=0;i< getNumberOfArguments() ;i++){ - comp=getPntrToArgument(i)->getName()+"_cntr"; // each spring has its own center - addComponent(comp); componentIsNotPeriodic(comp); - comp=getPntrToArgument(i)->getName()+"_work"; // each spring has its own work - addComponent(comp); componentIsNotPeriodic(comp); - comp=getPntrToArgument(i)->getName()+"_kappa"; // each spring has its own kappa - addComponent(comp); componentIsNotPeriodic(comp); - work.push_back(0.); // initialize the work value + for(unsigned i=0; i< getNumberOfArguments() ; i++) { + comp=getPntrToArgument(i)->getName()+"_cntr"; // each spring has its own center + addComponent(comp); componentIsNotPeriodic(comp); + comp=getPntrToArgument(i)->getName()+"_work"; // each spring has its own work + addComponent(comp); componentIsNotPeriodic(comp); + comp=getPntrToArgument(i)->getName()+"_kappa"; // each spring has its own kappa + addComponent(comp); componentIsNotPeriodic(comp); + work.push_back(0.); // initialize the work value } addComponent("work"); componentIsNotPeriodic("work"); tot_work=0.0; @@ -208,38 +208,38 @@ verse(getNumberOfArguments()) } -void MovingRestraint::calculate(){ +void MovingRestraint::calculate() { double ene=0.0; double totf2=0.0; unsigned narg=getNumberOfArguments(); long int now=getStep(); std::vector<double> kk(narg),aa(narg),f(narg),dpotdk(narg); - if(now<=step[0]){ + if(now<=step[0]) { kk=kappa[0]; aa=at[0]; oldaa=at[0]; oldk=kappa[0]; - olddpotdk.resize(narg); + olddpotdk.resize(narg); oldf.resize(narg); - } else if(now>=step[step.size()-1]){ + } else if(now>=step[step.size()-1]) { kk=kappa[step.size()-1]; aa=at[step.size()-1]; } else { unsigned i=0; - for(i=1;i<step.size();i++) if(now<step[i]) break; + for(i=1; i<step.size(); i++) if(now<step[i]) break; double c2=(now-step[i-1])/double(step[i]-step[i-1]); double c1=1.0-c2; - for(unsigned j=0;j<narg;j++) kk[j]=(c1*kappa[i-1][j]+c2*kappa[i][j]); - for(unsigned j=0;j<narg;j++) { + for(unsigned j=0; j<narg; j++) kk[j]=(c1*kappa[i-1][j]+c2*kappa[i][j]); + for(unsigned j=0; j<narg; j++) { const double a1=at[i-1][j]; const double a2=at[i][j]; aa[j]=(c1*a1+c2*(a1+difference(j,a1,a2))); } } tot_work=0.0; - for(unsigned i=0;i<narg;++i){ + for(unsigned i=0; i<narg; ++i) { const double cv=difference(i,aa[i],getArgument(i)); // this gives: getArgument(i) - aa[i] - getPntrToComponent(getPntrToArgument(i)->getName()+"_cntr")->set(aa[i]); + getPntrToComponent(getPntrToArgument(i)->getName()+"_cntr")->set(aa[i]); const double k=kk[i]; f[i]=-k*cv; if(verse[i]=="U" && cv<0) continue; @@ -247,8 +247,8 @@ void MovingRestraint::calculate(){ plumed_assert(verse[i]=="U" || verse[i]=="L" || verse[i]=="B"); dpotdk[i]=0.5*cv*cv; if(oldaa.size()==aa.size() && oldf.size()==f.size()) work[i]+=0.5*(oldf[i]+f[i])*(aa[i]-oldaa[i]) + 0.5*( dpotdk[i]+olddpotdk[i] )*(kk[i]-oldk[i]); - getPntrToComponent(getPntrToArgument(i)->getName()+"_work")->set(work[i]); - getPntrToComponent(getPntrToArgument(i)->getName()+"_kappa")->set(kk[i]); + getPntrToComponent(getPntrToArgument(i)->getName()+"_work")->set(work[i]); + getPntrToComponent(getPntrToArgument(i)->getName()+"_kappa")->set(kk[i]); tot_work+=work[i]; ene+=0.5*k*cv*cv; setOutputForce(i,f[i]); diff --git a/src/bias/PBMetaD.cpp b/src/bias/PBMetaD.cpp index a129ffb9c..b50557f7d 100644 --- a/src/bias/PBMetaD.cpp +++ b/src/bias/PBMetaD.cpp @@ -41,14 +41,14 @@ using namespace std; -namespace PLMD{ -namespace bias{ +namespace PLMD { +namespace bias { -//+PLUMEDOC BIAS PBMETAD +//+PLUMEDOC BIAS PBMETAD /* Used to performed Parallel Bias MetaDynamics. -This action activate Parallel Bias MetaDynamics (PBMetaD) \cite pbmetad, a version of MetaDynamics \cite metad in which +This action activate Parallel Bias MetaDynamics (PBMetaD) \cite pbmetad, a version of MetaDynamics \cite metad in which multiple low-dimensional bias potentials are applied in parallel. In the current implementation, these have the form of mono-dimensional MetaDynamics bias potentials: @@ -72,7 +72,7 @@ at each deposition step the Gaussian heights are multiplied by the so-called con \f[ W_i(k \tau)=W_0 \frac{\exp\left( - \frac{V(s_i,k \tau)}{k_B T} -\right)}{\sum_{i=1}^N +\right)}{\sum_{i=1}^N \exp\left( - \frac{V(s_i,k \tau)}{k_B T} \right)} @@ -83,19 +83,19 @@ where \f$W_0\f$ is the initial Gaussian height. The PBMetaD bias potential is defined by: \f[ -V_{PB}(\vec{s},t) = -k_B T \log{\sum_{i=1}^N +V_{PB}(\vec{s},t) = -k_B T \log{\sum_{i=1}^N \exp\left( - \frac{V(s_i,t)}{k_B T} \right)}. \f] -Information on the Gaussian functions that build each bias potential are printed to -multiple HILLS files, which -are used both to restart the calculation and to reconstruct the mono-dimensional -free energies as a function of the corresponding CVs. +Information on the Gaussian functions that build each bias potential are printed to +multiple HILLS files, which +are used both to restart the calculation and to reconstruct the mono-dimensional +free energies as a function of the corresponding CVs. These can be reconstructed using the \ref sum_hills utility because the final bias is given -by: +by: \f[ V(s_i) = -F(s_i) @@ -113,7 +113,7 @@ and if Gaussian width is fixed PLUMED will use 1/5 of the Gaussian width as grid This default choice should be reasonable for most applications. Another option that is available is well-tempered metadynamics \cite Barducci:2008. In this -variant of PBMetaD the heights of the Gaussian hills are rescaled at each step by the +variant of PBMetaD the heights of the Gaussian hills are rescaled at each step by the additional well-tempered metadynamics term. This ensures that each bias converges more smoothly. It should be noted that, in the case of well-tempered metadynamics, in the output printed the Gaussian height is re-scaled using the bias factor. @@ -128,21 +128,21 @@ gaussian potential is denoted by one value only that is a Cartesian space (ADAPT (ADAPTIVE=DIFF). Note that a specific integration technique for the deposited gaussians should be used in this case. Check the documentation for utility sum_hills. -With the keyword INTERVAL one changes the metadynamics algorithm setting the bias force equal to zero -outside boundary \cite baftizadeh2012protein. If, for example, metadynamics is performed on a CV s and one is interested only +With the keyword INTERVAL one changes the metadynamics algorithm setting the bias force equal to zero +outside boundary \cite baftizadeh2012protein. If, for example, metadynamics is performed on a CV s and one is interested only to the free energy for s > sw, the history dependent potential is still updated according to the above -equations but the metadynamics force is set to zero for s < sw. Notice that Gaussians are added also -if s < sw, as the tails of these Gaussians influence VG in the relevant region s > sw. In this way, the -force on the system in the region s > sw comes from both metadynamics and the force field, in the region -s < sw only from the latter. This approach allows obtaining a history-dependent bias potential VG that -fluctuates around a stable estimator, equal to the negative of the free energy far enough from the +equations but the metadynamics force is set to zero for s < sw. Notice that Gaussians are added also +if s < sw, as the tails of these Gaussians influence VG in the relevant region s > sw. In this way, the +force on the system in the region s > sw comes from both metadynamics and the force field, in the region +s < sw only from the latter. This approach allows obtaining a history-dependent bias potential VG that +fluctuates around a stable estimator, equal to the negative of the free energy far enough from the boundaries. Note that: - It works only for one-dimensional biases; - It works both with and without GRID; - The interval limit sw in a region where the free energy derivative is not large; -- If in the region outside the limit sw the system has a free energy minimum, the INTERVAL keyword should +- If in the region outside the limit sw the system has a free energy minimum, the INTERVAL keyword should be used together with a \ref UPPER_WALLS or \ref LOWER_WALLS at sw. - + Multiple walkers \cite multiplewalkers can also be used. See below the examples. \par Examples @@ -160,26 +160,26 @@ PRINT ARG=d1,d2,pb.bias STRIDE=100 FILE=COLVAR \par If you use well-tempered metadynamics, you should specify a single biasfactor and initial -Gaussian height. +Gaussian height. \verbatim DISTANCE ATOMS=3,5 LABEL=d1 DISTANCE ATOMS=2,4 LABEL=d2 PBMETAD ... -ARG=d1,d2 SIGMA=0.2,0.2 HEIGHT=0.3 -PACE=500 BIASFACTOR=8 LABEL=pb +ARG=d1,d2 SIGMA=0.2,0.2 HEIGHT=0.3 +PACE=500 BIASFACTOR=8 LABEL=pb FILE=HILLS_d1,HILLS_d2 ... PBMETAD PRINT ARG=d1,d2,pb.bias STRIDE=100 FILE=COLVAR \endverbatim -\par +\par The following input enables the MPI version of multiple-walkers. \verbatim DISTANCE ATOMS=3,5 LABEL=d1 DISTANCE ATOMS=2,4 LABEL=d2 PBMETAD ... -ARG=d1,d2 SIGMA=0.2,0.2 HEIGHT=0.3 -PACE=500 BIASFACTOR=8 LABEL=pb +ARG=d1,d2 SIGMA=0.2,0.2 HEIGHT=0.3 +PACE=500 BIASFACTOR=8 LABEL=pb FILE=HILLS_d1,HILLS_d2 WALKERS_MPI ... PBMETAD @@ -187,17 +187,17 @@ PRINT ARG=d1,d2,pb.bias STRIDE=100 FILE=COLVAR \endverbatim \par -The disk version of multiple-walkers can be -enabled by setting the number of walker used, the id of the -current walker which interprets the input file, the directory where the +The disk version of multiple-walkers can be +enabled by setting the number of walker used, the id of the +current walker which interprets the input file, the directory where the hills containing files resides, and the frequency to read the other walkers. Here is an example \verbatim DISTANCE ATOMS=3,5 LABEL=d1 DISTANCE ATOMS=2,4 LABEL=d2 PBMETAD ... -ARG=d1,d2 SIGMA=0.2,0.2 HEIGHT=0.3 -PACE=500 BIASFACTOR=8 LABEL=pb +ARG=d1,d2 SIGMA=0.2,0.2 HEIGHT=0.3 +PACE=500 BIASFACTOR=8 LABEL=pb FILE=HILLS_d1,HILLS_d2 WALKERS_N=10 WALKERS_ID=3 @@ -206,28 +206,28 @@ WALKERS_RSTRIDE=100 ... PBMETAD PRINT ARG=d1,d2,pb.bias STRIDE=100 FILE=COLVAR \endverbatim -where WALKERS_N is the total number of walkers, WALKERS_ID is the -id of the present walker (starting from 0 ) and the WALKERS_DIR is the directory -where all the walkers are located. WALKERS_RSTRIDE is the number of step between -one update and the other. +where WALKERS_N is the total number of walkers, WALKERS_ID is the +id of the present walker (starting from 0 ) and the WALKERS_DIR is the directory +where all the walkers are located. WALKERS_RSTRIDE is the number of step between +one update and the other. */ //+ENDPLUMEDOC -class PBMetaD : public Bias{ +class PBMetaD : public Bias { private: struct Gaussian { - vector<double> center; - vector<double> sigma; - double height; - bool multivariate; // this is required to discriminate the one dimensional case - vector<double> invsigma; - Gaussian(const vector<double> & center,const vector<double> & sigma, double height, bool multivariate): - center(center),sigma(sigma),height(height),multivariate(multivariate),invsigma(sigma){ - // to avoid troubles from zero element in flexible hills - for(unsigned i=0;i<invsigma.size();++i) abs(invsigma[i])>1.e-20?invsigma[i]=1.0/invsigma[i]:0.; - } + vector<double> center; + vector<double> sigma; + double height; + bool multivariate; // this is required to discriminate the one dimensional case + vector<double> invsigma; + Gaussian(const vector<double> & center,const vector<double> & sigma, double height, bool multivariate): + center(center),sigma(sigma),height(height),multivariate(multivariate),invsigma(sigma) { + // to avoid troubles from zero element in flexible hills + for(unsigned i=0; i<invsigma.size(); ++i) abs(invsigma[i])>1.e-20?invsigma[i]=1.0/invsigma[i]:0.; + } }; vector<double> sigma0_; vector<double> sigma0min_; @@ -276,12 +276,12 @@ public: void calculate(); void update(); static void registerKeywords(Keywords& keys); - bool checkNeedsGradients()const{if(adaptive_==FlexibleBin::geometry){return true;}else{return false;}} + bool checkNeedsGradients()const {if(adaptive_==FlexibleBin::geometry) {return true;} else {return false;}} }; PLUMED_REGISTER_ACTION(PBMetaD,"PBMETAD") -void PBMetaD::registerKeywords(Keywords& keys){ +void PBMetaD::registerKeywords(Keywords& keys) { Bias::registerKeywords(keys); keys.use("ARG"); keys.add("compulsory","SIGMA","the widths of the Gaussian hills"); @@ -316,102 +316,102 @@ void PBMetaD::registerKeywords(Keywords& keys){ keys.use("UPDATE_UNTIL"); } -PBMetaD::~PBMetaD(){ +PBMetaD::~PBMetaD() { for(unsigned i=0; i<BiasGrids_.size(); ++i) delete BiasGrids_[i]; - for(unsigned i=0; i<hillsOfiles_.size(); ++i){ - hillsOfiles_[i]->close(); - delete hillsOfiles_[i]; + for(unsigned i=0; i<hillsOfiles_.size(); ++i) { + hillsOfiles_[i]->close(); + delete hillsOfiles_[i]; } if(wgridstride_ > 0) { - for(unsigned i=0; i<gridfiles_.size(); ++i) { - gridfiles_[i]->close(); - delete gridfiles_[i]; - } + for(unsigned i=0; i<gridfiles_.size(); ++i) { + gridfiles_[i]->close(); + delete gridfiles_[i]; + } } // close files - for(unsigned i=0;i<ifiles.size();++i){ - if(ifiles[i]->isOpen()) ifiles[i]->close(); - delete ifiles[i]; + for(unsigned i=0; i<ifiles.size(); ++i) { + if(ifiles[i]->isOpen()) ifiles[i]->close(); + delete ifiles[i]; } } PBMetaD::PBMetaD(const ActionOptions& ao): -PLUMED_BIAS_INIT(ao), -grid_(false), height0_(std::numeric_limits<double>::max()), -biasf_(1.0), kbt_(0.0), stride_(0), wgridstride_(0), welltemp_(false), -mw_n_(1), mw_dir_(""), mw_id_(0), mw_rstride_(1), -walkers_mpi(false), mpi_nw_(0), -adaptive_(FlexibleBin::none), -isFirstStep(true) + PLUMED_BIAS_INIT(ao), + grid_(false), height0_(std::numeric_limits<double>::max()), + biasf_(1.0), kbt_(0.0), stride_(0), wgridstride_(0), welltemp_(false), + mw_n_(1), mw_dir_(""), mw_id_(0), mw_rstride_(1), + walkers_mpi(false), mpi_nw_(0), + adaptive_(FlexibleBin::none), + isFirstStep(true) { // parse the flexible hills string adaptiveoption; adaptiveoption="NONE"; parse("ADAPTIVE",adaptiveoption); - if(adaptiveoption=="GEOM"){ + if(adaptiveoption=="GEOM") { log.printf(" Uses Geometry-based hills width: sigma must be in distance units and only one sigma is needed\n"); - adaptive_=FlexibleBin::geometry; - } else if(adaptiveoption=="DIFF"){ + adaptive_=FlexibleBin::geometry; + } else if(adaptiveoption=="DIFF") { log.printf(" Uses Diffusion-based hills width: sigma must be in timesteps and only one sigma is needed\n"); - adaptive_=FlexibleBin::diffusion; - } else if(adaptiveoption=="NONE"){ - adaptive_=FlexibleBin::none; + adaptive_=FlexibleBin::diffusion; + } else if(adaptiveoption=="NONE") { + adaptive_=FlexibleBin::none; } else { - error("I do not know this type of adaptive scheme"); + error("I do not know this type of adaptive scheme"); } parse("FMT",fmt); // parse the sigma parseVector("SIGMA",sigma0_); - if(adaptive_==FlexibleBin::none){ - // if you use normal sigma you need one sigma per argument + if(adaptive_==FlexibleBin::none) { + // if you use normal sigma you need one sigma per argument if( sigma0_.size()!=getNumberOfArguments() ) error("number of arguments does not match number of SIGMA parameters"); } else { - // if you use flexible hills you need one sigma - if(sigma0_.size()!=1){ + // if you use flexible hills you need one sigma + if(sigma0_.size()!=1) { error("If you choose ADAPTIVE you need only one sigma according to your choice of type (GEOM/DIFF)"); - } + } // if adaptive then the number must be an integer - if(adaptive_==FlexibleBin::diffusion){ - if(int(sigma0_[0])-sigma0_[0]>1.e-9 || int(sigma0_[0])-sigma0_[0] <-1.e-9 || int(sigma0_[0])<1 ){ - error("In case of adaptive hills with diffusion, the sigma must be an integer which is the number of timesteps\n"); - } - } + if(adaptive_==FlexibleBin::diffusion) { + if(int(sigma0_[0])-sigma0_[0]>1.e-9 || int(sigma0_[0])-sigma0_[0] <-1.e-9 || int(sigma0_[0])<1 ) { + error("In case of adaptive hills with diffusion, the sigma must be an integer which is the number of timesteps\n"); + } + } // here evtl parse the sigma min and max values parseVector("SIGMA_MIN",sigma0min_); if(sigma0min_.size()>0 && sigma0min_.size()!=getNumberOfArguments()) { error("the number of SIGMA_MIN values be the same of the number of the arguments"); - } else if(sigma0min_.size()==0) { + } else if(sigma0min_.size()==0) { sigma0min_.resize(getNumberOfArguments()); - for(unsigned i=0;i<getNumberOfArguments();i++){sigma0min_[i]=-1.;} + for(unsigned i=0; i<getNumberOfArguments(); i++) {sigma0min_[i]=-1.;} } - + parseVector("SIGMA_MAX",sigma0max_); if(sigma0max_.size()>0 && sigma0max_.size()!=getNumberOfArguments()) { - error("the number of SIGMA_MAX values be the same of the number of the arguments"); - } else if(sigma0max_.size()==0) { + error("the number of SIGMA_MAX values be the same of the number of the arguments"); + } else if(sigma0max_.size()==0) { sigma0max_.resize(getNumberOfArguments()); - for(unsigned i=0;i<getNumberOfArguments();i++){sigma0max_[i]=-1.;} + for(unsigned i=0; i<getNumberOfArguments(); i++) {sigma0max_[i]=-1.;} } - - for(unsigned i=0;i<getNumberOfArguments();i++) { + + for(unsigned i=0; i<getNumberOfArguments(); i++) { vector<double> tmp_smin, tmp_smax; tmp_smin.resize(1,sigma0min_[i]); tmp_smax.resize(1,sigma0max_[i]); flexbin.push_back(FlexibleBin(adaptive_,this,i,sigma0_[0],tmp_smin,tmp_smax)); } } - + // note: HEIGHT is not compulsory, since one could use the TAU keyword, see below parse("HEIGHT",height0_); parse("PACE",stride_); if(stride_<=0) error("frequency for hill addition is nonsensical"); - + parseVector("FILE",hillsfname); if(hillsfname.size()==0) { - for(unsigned i=0;i<getNumberOfArguments();i++) hillsfname.push_back("HILLS."+getPntrToArgument(i)->getName()); - } + for(unsigned i=0; i<getNumberOfArguments(); i++) hillsfname.push_back("HILLS."+getPntrToArgument(i)->getName()); + } if( hillsfname.size()!=getNumberOfArguments() ) { error("number of FILE arguments does not match number of HILLS files"); } @@ -422,13 +422,13 @@ isFirstStep(true) parse("TEMP",temp); if(temp>0.0) kbt_=plumed.getAtoms().getKBoltzmann()*temp; else kbt_=plumed.getAtoms().getKbT(); - if(biasf_>1.0){ + if(biasf_>1.0) { if(kbt_==0.0) error("Unless the MD engine passes the temperature to plumed, with well-tempered metad you must specify it using TEMP"); welltemp_=true; } double tau=0.0; parse("TAU",tau); - if(tau==0.0){ + if(tau==0.0) { if(height0_==std::numeric_limits<double>::max()) error("At least one between HEIGHT and TAU should be specified"); // if tau is not set, we compute it here from the other input parameters if(welltemp_) tau=(kbt_*(biasf_-1.0))/height0_*getTimeStep()*stride_; @@ -437,7 +437,7 @@ isFirstStep(true) if(height0_!=std::numeric_limits<double>::max()) error("At most one between HEIGHT and TAU should be specified"); height0_=(kbt_*(biasf_-1.0))/tau*getTimeStep()*stride_; } - + // Multiple walkers parse("WALKERS_N",mw_n_); parse("WALKERS_ID",mw_id_); @@ -456,15 +456,15 @@ isFirstStep(true) error("frequency with which to output grid not specified use GRID_WSTRIDE"); } if(gridfilenames_.size()==0 && wgridstride_ > 0) { - for(unsigned i=0;i<getNumberOfArguments();i++) gridfilenames_.push_back("GRID."+getPntrToArgument(i)->getName()); - } - if(gridfilenames_.size() > 0 && hillsfname.size() > 0 && gridfilenames_.size() != hillsfname.size()) + for(unsigned i=0; i<getNumberOfArguments(); i++) gridfilenames_.push_back("GRID."+getPntrToArgument(i)->getName()); + } + if(gridfilenames_.size() > 0 && hillsfname.size() > 0 && gridfilenames_.size() != hillsfname.size()) error("number of GRID_WFILES arguments does not match number of HILLS files"); // Read grid vector<string> gridreadfilenames_; parseVector("GRID_RFILES",gridreadfilenames_); - + // Grid Stuff vector<std::string> gmin(getNumberOfArguments()); parseVector("GRID_MIN",gmin); @@ -481,45 +481,45 @@ isFirstStep(true) if(gmin.size()!=gmax.size()) error("GRID_MAX and GRID_MIN should be either present or absent"); if(gspacing.size()!=0 && gmin.size()==0) error("If GRID_SPACING is present also GRID_MIN should be present"); if(gbin.size()!=0 && gmin.size()==0) error("If GRID_SPACING is present also GRID_MIN should be present"); - if(gmin.size()!=0){ - if(gbin.size()==0 && gspacing.size()==0){ - if(adaptive_==FlexibleBin::none){ + if(gmin.size()!=0) { + if(gbin.size()==0 && gspacing.size()==0) { + if(adaptive_==FlexibleBin::none) { log<<" Binsize not specified, 1/10 of sigma will be be used\n"; plumed_assert(sigma0_.size()==getNumberOfArguments()); gspacing.resize(getNumberOfArguments()); - for(unsigned i=0;i<gspacing.size();i++) gspacing[i]=0.1*sigma0_[i]; + for(unsigned i=0; i<gspacing.size(); i++) gspacing[i]=0.1*sigma0_[i]; } else { // with adaptive hills and grid a sigma min must be specified - for(unsigned i=0;i<sigma0min_.size();i++) if(sigma0min_[i]<=0) error("When using Adaptive Gaussians on a grid SIGMA_MIN must be specified"); + for(unsigned i=0; i<sigma0min_.size(); i++) if(sigma0min_[i]<=0) error("When using Adaptive Gaussians on a grid SIGMA_MIN must be specified"); log<<" Binsize not specified, 1/5 of sigma_min will be be used\n"; gspacing.resize(getNumberOfArguments()); - for(unsigned i=0;i<gspacing.size();i++) gspacing[i]=0.2*sigma0min_[i]; + for(unsigned i=0; i<gspacing.size(); i++) gspacing[i]=0.2*sigma0min_[i]; } - } else if(gspacing.size()!=0 && gbin.size()==0){ + } else if(gspacing.size()!=0 && gbin.size()==0) { log<<" The number of bins will be estimated from GRID_SPACING\n"; - } else if(gspacing.size()!=0 && gbin.size()!=0){ + } else if(gspacing.size()!=0 && gbin.size()!=0) { log<<" You specified both GRID_BIN and GRID_SPACING\n"; log<<" The more conservative (highest) number of bins will be used for each variable\n"; } if(gbin.size()==0) gbin.assign(getNumberOfArguments(),1); - if(gspacing.size()!=0) for(unsigned i=0;i<getNumberOfArguments();i++){ - double a,b; - Tools::convert(gmin[i],a); - Tools::convert(gmax[i],b); - unsigned n=((b-a)/gspacing[i])+1; - if(gbin[i]<n) gbin[i]=n; - } + if(gspacing.size()!=0) for(unsigned i=0; i<getNumberOfArguments(); i++) { + double a,b; + Tools::convert(gmin[i],a); + Tools::convert(gmax[i],b); + unsigned n=((b-a)/gspacing[i])+1; + if(gbin[i]<n) gbin[i]=n; + } } bool sparsegrid=false; parseFlag("GRID_SPARSE",sparsegrid); bool nospline=false; parseFlag("GRID_NOSPLINE",nospline); bool spline=!nospline; - if(gbin.size()>0){grid_=true;} + if(gbin.size()>0) {grid_=true;} if(!grid_&&gridfilenames_.size() > 0) error("To write a grid you need first to define it!"); if(!grid_&&gridreadfilenames_.size() > 0) error("To read a grid you need first to define it!"); - doInt_.resize(getNumberOfArguments(),false); + doInt_.resize(getNumberOfArguments(),false); // Interval keyword parseVector("INTERVAL_MIN",lowI_); parseVector("INTERVAL_MAX",uppI_); @@ -531,26 +531,26 @@ isFirstStep(true) if(getPntrToArgument(i)->isPeriodic()) warning("INTERVAL is not used for periodic variables"); else doInt_[i]=true; } - + checkRead(); log.printf(" Gaussian width "); if (adaptive_==FlexibleBin::diffusion)log.printf(" (Note: The units of sigma are in timesteps) "); if (adaptive_==FlexibleBin::geometry)log.printf(" (Note: The units of sigma are in dist units) "); - for(unsigned i=0;i<sigma0_.size();++i) log.printf(" %f",sigma0_[i]); + for(unsigned i=0; i<sigma0_.size(); ++i) log.printf(" %f",sigma0_[i]); log.printf(" Gaussian height %f\n",height0_); - log.printf(" Gaussian deposition pace %d\n",stride_); + log.printf(" Gaussian deposition pace %d\n",stride_); log.printf(" Gaussian files "); for(unsigned i=0; i<hillsfname.size(); ++i) log.printf("%s ",hillsfname[i].c_str()); log.printf("\n"); - if(welltemp_){ + if(welltemp_) { log.printf(" Well-Tempered Bias Factor %f\n",biasf_); log.printf(" Hills relaxation time (tau) %f\n",tau); log.printf(" KbT %f\n",kbt_); } - if(mw_n_>1){ + if(mw_n_>1) { if(walkers_mpi) error("MPI version of multiple walkers is not compatible with filesystem version of multiple walkers"); log.printf(" %d multiple walkers active\n",mw_n_); log.printf(" walker id %d\n",mw_id_); @@ -558,9 +558,9 @@ isFirstStep(true) if(mw_dir_!="")log.printf(" directory with hills files %s\n",mw_dir_.c_str()); } else { if(walkers_mpi) { - log.printf(" Multiple walkers active using MPI communnication\n"); + log.printf(" Multiple walkers active using MPI communnication\n"); if(mw_dir_!="")log.printf(" directory with hills files %s\n",mw_dir_.c_str()); - if(comm.Get_rank()==0){ + if(comm.Get_rank()==0) { // Only root of group can communicate with other walkers mpi_nw_ = multi_sim_comm.Get_size(); mpi_id_ = multi_sim_comm.Get_rank(); @@ -572,31 +572,31 @@ isFirstStep(true) } } - for(unsigned i=0; i<doInt_.size();i++) { + for(unsigned i=0; i<doInt_.size(); i++) { if(doInt_[i]) log.printf(" Upper and Lower limits boundaries for the bias of CV %u are activated\n", i); } - if(grid_){ - log.printf(" Grid min"); - for(unsigned i=0;i<gmin.size();++i) log.printf(" %s",gmin[i].c_str() ); - log.printf("\n"); - log.printf(" Grid max"); - for(unsigned i=0;i<gmax.size();++i) log.printf(" %s",gmax[i].c_str() ); - log.printf("\n"); - log.printf(" Grid bin"); - for(unsigned i=0;i<gbin.size();++i) log.printf(" %u",gbin[i]); - log.printf("\n"); - if(spline){log.printf(" Grid uses spline interpolation\n");} - if(sparsegrid){log.printf(" Grid uses sparse grid\n");} - if(wgridstride_>0) { - for(unsigned i=0; i<gridfilenames_.size(); ++i) { - log.printf(" Grid is written on file %s with stride %d\n",gridfilenames_[i].c_str(),wgridstride_); + if(grid_) { + log.printf(" Grid min"); + for(unsigned i=0; i<gmin.size(); ++i) log.printf(" %s",gmin[i].c_str() ); + log.printf("\n"); + log.printf(" Grid max"); + for(unsigned i=0; i<gmax.size(); ++i) log.printf(" %s",gmax[i].c_str() ); + log.printf("\n"); + log.printf(" Grid bin"); + for(unsigned i=0; i<gbin.size(); ++i) log.printf(" %u",gbin[i]); + log.printf("\n"); + if(spline) {log.printf(" Grid uses spline interpolation\n");} + if(sparsegrid) {log.printf(" Grid uses sparse grid\n");} + if(wgridstride_>0) { + for(unsigned i=0; i<gridfilenames_.size(); ++i) { + log.printf(" Grid is written on file %s with stride %d\n",gridfilenames_[i].c_str(),wgridstride_); + } } - } - if(gridreadfilenames_.size()>0) { - for(unsigned i=0; i<gridreadfilenames_.size(); ++i) { - log.printf(" Reading bias from grid in file %s \n",gridreadfilenames_[i].c_str()); + if(gridreadfilenames_.size()>0) { + for(unsigned i=0; i<gridreadfilenames_.size(); ++i) { + log.printf(" Reading bias from grid in file %s \n",gridreadfilenames_[i].c_str()); + } } - } } // initializing vector of hills @@ -606,67 +606,67 @@ isFirstStep(true) bool restartedFromGrid=false; // initializing and checking grid - if(grid_){ - // check for mesh and sigma size - for(unsigned i=0;i<getNumberOfArguments();i++) { - double a,b; - Tools::convert(gmin[i],a); - Tools::convert(gmax[i],b); - double mesh=(b-a)/((double)gbin[i]); - if(adaptive_==FlexibleBin::none) { - if(mesh>0.5*sigma0_[i]) log<<" WARNING: Using a METAD with a Grid Spacing larger than half of the Gaussians width can produce artifacts\n"; - } else { - if(mesh>0.5*sigma0min_[i]||sigma0min_[i]<0.) log<<" WARNING: to use a METAD with a GRID and ADAPTIVE you need to set a Grid Spacing larger than half of the Gaussians \n"; - } - } - std::string funcl=getLabel() + ".bias"; - for(unsigned i=0; i<getNumberOfArguments(); ++i){ - std::vector<Value*> args(1); - args[0] = getPntrToArgument(i); - vector<std::string> gmin_t(1); - vector<std::string> gmax_t(1); - vector<unsigned> gbin_t(1); - gmin_t[0] = gmin[i]; - gmax_t[0] = gmax[i]; - gbin_t[0] = gbin[i]; - Grid* BiasGrid_; - // Read grid from file - if(gridreadfilenames_.size()>0) { - IFile gridfile; - gridfile.link(*this); - if(gridfile.FileExist(gridreadfilenames_[i])){ - gridfile.open(gridreadfilenames_[i]); - } else { - error("The GRID file you want to read: " + gridreadfilenames_[i] + ", cannot be found!"); - } - string funcl = getLabel() + ".bias"; - BiasGrid_ = Grid::create(funcl, args, gridfile, gmin_t, gmax_t, gbin_t, sparsegrid, spline, true); - gridfile.close(); - if(BiasGrid_->getDimension() != args.size()) { - error("mismatch between dimensionality of input grid and number of arguments"); - } - if(getPntrToArgument(i)->isPeriodic() != BiasGrid_->getIsPeriodic()[0]) { - error("periodicity mismatch between arguments and input bias"); - } - log.printf(" Restarting from %s:",gridreadfilenames_[i].c_str()); - if(getRestart()) restartedFromGrid=true; - } else { - if(!sparsegrid){BiasGrid_=new Grid(funcl,args,gmin_t,gmax_t,gbin_t,spline,true);} - else {BiasGrid_=new SparseGrid(funcl,args,gmin_t,gmax_t,gbin_t,spline,true);} - std::vector<std::string> actualmin=BiasGrid_->getMin(); - std::vector<std::string> actualmax=BiasGrid_->getMax(); - if(gmin_t[0]!=actualmin[0]) log<<" WARNING: GRID_MIN["<<i<<"] has been adjusted to "<<actualmin[0]<<" to fit periodicity\n"; - if(gmax_t[0]!=actualmax[0]) log<<" WARNING: GRID_MAX["<<i<<"] has been adjusted to "<<actualmax[0]<<" to fit periodicity\n"; + if(grid_) { + // check for mesh and sigma size + for(unsigned i=0; i<getNumberOfArguments(); i++) { + double a,b; + Tools::convert(gmin[i],a); + Tools::convert(gmax[i],b); + double mesh=(b-a)/((double)gbin[i]); + if(adaptive_==FlexibleBin::none) { + if(mesh>0.5*sigma0_[i]) log<<" WARNING: Using a METAD with a Grid Spacing larger than half of the Gaussians width can produce artifacts\n"; + } else { + if(mesh>0.5*sigma0min_[i]||sigma0min_[i]<0.) log<<" WARNING: to use a METAD with a GRID and ADAPTIVE you need to set a Grid Spacing larger than half of the Gaussians \n"; + } + } + std::string funcl=getLabel() + ".bias"; + for(unsigned i=0; i<getNumberOfArguments(); ++i) { + std::vector<Value*> args(1); + args[0] = getPntrToArgument(i); + vector<std::string> gmin_t(1); + vector<std::string> gmax_t(1); + vector<unsigned> gbin_t(1); + gmin_t[0] = gmin[i]; + gmax_t[0] = gmax[i]; + gbin_t[0] = gbin[i]; + Grid* BiasGrid_; + // Read grid from file + if(gridreadfilenames_.size()>0) { + IFile gridfile; + gridfile.link(*this); + if(gridfile.FileExist(gridreadfilenames_[i])) { + gridfile.open(gridreadfilenames_[i]); + } else { + error("The GRID file you want to read: " + gridreadfilenames_[i] + ", cannot be found!"); + } + string funcl = getLabel() + ".bias"; + BiasGrid_ = Grid::create(funcl, args, gridfile, gmin_t, gmax_t, gbin_t, sparsegrid, spline, true); + gridfile.close(); + if(BiasGrid_->getDimension() != args.size()) { + error("mismatch between dimensionality of input grid and number of arguments"); + } + if(getPntrToArgument(i)->isPeriodic() != BiasGrid_->getIsPeriodic()[0]) { + error("periodicity mismatch between arguments and input bias"); + } + log.printf(" Restarting from %s:",gridreadfilenames_[i].c_str()); + if(getRestart()) restartedFromGrid=true; + } else { + if(!sparsegrid) {BiasGrid_=new Grid(funcl,args,gmin_t,gmax_t,gbin_t,spline,true);} + else {BiasGrid_=new SparseGrid(funcl,args,gmin_t,gmax_t,gbin_t,spline,true);} + std::vector<std::string> actualmin=BiasGrid_->getMin(); + std::vector<std::string> actualmax=BiasGrid_->getMax(); + if(gmin_t[0]!=actualmin[0]) log<<" WARNING: GRID_MIN["<<i<<"] has been adjusted to "<<actualmin[0]<<" to fit periodicity\n"; + if(gmax_t[0]!=actualmax[0]) log<<" WARNING: GRID_MAX["<<i<<"] has been adjusted to "<<actualmax[0]<<" to fit periodicity\n"; + } + BiasGrids_.push_back(BiasGrid_); } - BiasGrids_.push_back(BiasGrid_); - } } -// creating vector of ifile* for hills reading +// creating vector of ifile* for hills reading // open all files at the beginning and read Gaussians if restarting - for(int j=0;j<mw_n_;++j){ - for(unsigned i=0;i<hillsfname.size();++i){ + for(int j=0; j<mw_n_; ++j) { + for(unsigned i=0; i<hillsfname.size(); ++i) { unsigned k=j*hillsfname.size()+i; string fname; if(mw_dir_!="") { @@ -690,9 +690,9 @@ isFirstStep(true) ifile->link(*this); ifiles.push_back(ifile); ifilesnames.push_back(fname); - if(ifile->FileExist(fname)){ + if(ifile->FileExist(fname)) { ifile->open(fname); - if(getRestart()&&!restartedFromGrid){ + if(getRestart()&&!restartedFromGrid) { log.printf(" Restarting from %s:",ifilesnames[k].c_str()); readGaussians(i,ifiles[k]); } @@ -707,106 +707,108 @@ isFirstStep(true) if(comm.Get_rank()==0 && walkers_mpi) multi_sim_comm.Barrier(); // open hills files for writing - for(unsigned i=0;i<hillsfname.size();++i){ - OFile *ofile = new OFile(); - ofile->link(*this); - // if MPI multiple walkers, only rank 0 will write to file - if(walkers_mpi){ - int r=0; - if(comm.Get_rank()==0) r=multi_sim_comm.Get_rank(); - comm.Bcast(r,0); - if(r>0) ifilesnames[mw_id_*hillsfname.size()+i]="/dev/null"; - ofile->enforceSuffix(""); - } - if(mw_n_>1) ofile->enforceSuffix(""); - ofile->open(ifilesnames[mw_id_*hillsfname.size()+i]); - if(fmt.length()>0) ofile->fmtField(fmt); - ofile->addConstantField("multivariate"); - if(doInt_[i]) { - ofile->addConstantField("lower_int").printField("lower_int",lowI_[i]); - ofile->addConstantField("upper_int").printField("upper_int",uppI_[i]); - } - ofile->setHeavyFlush(); - // output periodicities of variables - ofile->setupPrintValue( getPntrToArgument(i) ); - // push back - hillsOfiles_.push_back(ofile); - } - - // Dump grid to files - if(wgridstride_ > 0) { - for(unsigned i = 0; i < gridfilenames_.size(); ++i) { + for(unsigned i=0; i<hillsfname.size(); ++i) { OFile *ofile = new OFile(); ofile->link(*this); - string gridfname_tmp = gridfilenames_[i]; + // if MPI multiple walkers, only rank 0 will write to file if(walkers_mpi) { - int r = 0; - if(comm.Get_rank() == 0) { - r = multi_sim_comm.Get_rank(); - } - comm.Bcast(r, 0); - if(r>0) { - gridfname_tmp = "/dev/null"; - } - ofile->enforceSuffix(""); + int r=0; + if(comm.Get_rank()==0) r=multi_sim_comm.Get_rank(); + comm.Bcast(r,0); + if(r>0) ifilesnames[mw_id_*hillsfname.size()+i]="/dev/null"; + ofile->enforceSuffix(""); } if(mw_n_>1) ofile->enforceSuffix(""); - ofile->open(gridfname_tmp); + ofile->open(ifilesnames[mw_id_*hillsfname.size()+i]); + if(fmt.length()>0) ofile->fmtField(fmt); + ofile->addConstantField("multivariate"); + if(doInt_[i]) { + ofile->addConstantField("lower_int").printField("lower_int",lowI_[i]); + ofile->addConstantField("upper_int").printField("upper_int",uppI_[i]); + } ofile->setHeavyFlush(); - gridfiles_.push_back(ofile); - } + // output periodicities of variables + ofile->setupPrintValue( getPntrToArgument(i) ); + // push back + hillsOfiles_.push_back(ofile); + } + + // Dump grid to files + if(wgridstride_ > 0) { + for(unsigned i = 0; i < gridfilenames_.size(); ++i) { + OFile *ofile = new OFile(); + ofile->link(*this); + string gridfname_tmp = gridfilenames_[i]; + if(walkers_mpi) { + int r = 0; + if(comm.Get_rank() == 0) { + r = multi_sim_comm.Get_rank(); + } + comm.Bcast(r, 0); + if(r>0) { + gridfname_tmp = "/dev/null"; + } + ofile->enforceSuffix(""); + } + if(mw_n_>1) ofile->enforceSuffix(""); + ofile->open(gridfname_tmp); + ofile->setHeavyFlush(); + gridfiles_.push_back(ofile); + } } log<<" Bibliography "<<plumed.cite("Pfaendtner and Bonomi. J. Chem. Theory Comput. 11, 5062 (2015)"); if(doInt_[0]) log<<plumed.cite( - "Baftizadeh, Cossio, Pietrucci, and Laio, Curr. Phys. Chem. 2, 79 (2012)"); + "Baftizadeh, Cossio, Pietrucci, and Laio, Curr. Phys. Chem. 2, 79 (2012)"); if(mw_n_>1||walkers_mpi) log<<plumed.cite( - "Raiteri, Laio, Gervasio, Micheletti, and Parrinello, J. Phys. Chem. B 110, 3533 (2006)"); + "Raiteri, Laio, Gervasio, Micheletti, and Parrinello, J. Phys. Chem. B 110, 3533 (2006)"); if(adaptive_!=FlexibleBin::none) log<<plumed.cite( - "Branduardi, Bussi, and Parrinello, J. Chem. Theory Comput. 8, 2247 (2012)"); + "Branduardi, Bussi, and Parrinello, J. Chem. Theory Comput. 8, 2247 (2012)"); log<<"\n"; } void PBMetaD::readGaussians(unsigned iarg, IFile *ifile) { - vector<double> center(1); - vector<double> sigma(1); - double height; - int nhills=0; - bool multivariate=false; - - std::vector<Value> tmpvalues; - tmpvalues.push_back( Value( this, getPntrToArgument(iarg)->getName(), false ) ); - - while(scanOneHill(iarg,ifile,tmpvalues,center,sigma,height,multivariate)){; - nhills++; - if(welltemp_){height*=(biasf_-1.0)/biasf_;} - addGaussian(iarg, Gaussian(center,sigma,height,multivariate)); - } - log.printf(" %d Gaussians read\n",nhills); + vector<double> center(1); + vector<double> sigma(1); + double height; + int nhills=0; + bool multivariate=false; + + std::vector<Value> tmpvalues; + tmpvalues.push_back( Value( this, getPntrToArgument(iarg)->getName(), false ) ); + + while(scanOneHill(iarg,ifile,tmpvalues,center,sigma,height,multivariate)) { + ; + nhills++; + if(welltemp_) {height*=(biasf_-1.0)/biasf_;} + addGaussian(iarg, Gaussian(center,sigma,height,multivariate)); + } + log.printf(" %d Gaussians read\n",nhills); } bool PBMetaD::readChunkOfGaussians(unsigned iarg, IFile *ifile, unsigned n) { - vector<double> center(1); - vector<double> sigma(1); - double height; - unsigned nhills=0; - bool multivariate=false; - std::vector<Value> tmpvalues; - tmpvalues.push_back( Value( this, getPntrToArgument(iarg)->getName(), false ) ); - - while(scanOneHill(iarg,ifile,tmpvalues,center,sigma,height,multivariate)){; - if(welltemp_){height*=(biasf_-1.0)/biasf_;} - addGaussian(iarg, Gaussian(center,sigma,height,multivariate)); - if(nhills==n){ + vector<double> center(1); + vector<double> sigma(1); + double height; + unsigned nhills=0; + bool multivariate=false; + std::vector<Value> tmpvalues; + tmpvalues.push_back( Value( this, getPntrToArgument(iarg)->getName(), false ) ); + + while(scanOneHill(iarg,ifile,tmpvalues,center,sigma,height,multivariate)) { + ; + if(welltemp_) {height*=(biasf_-1.0)/biasf_;} + addGaussian(iarg, Gaussian(center,sigma,height,multivariate)); + if(nhills==n) { log.printf(" %u Gaussians read\n",nhills); return true; + } + nhills++; } - nhills++; - } - log.printf(" %u Gaussians read\n",nhills); - return false; + log.printf(" %u Gaussians read\n",nhills); + return false; } void PBMetaD::writeGaussian(unsigned iarg, const Gaussian& hill, OFile *ofile) @@ -814,17 +816,17 @@ void PBMetaD::writeGaussian(unsigned iarg, const Gaussian& hill, OFile *ofile) ofile->printField("time",getTimeStep()*getStep()); ofile->printField(getPntrToArgument(iarg),hill.center[0]); - if(hill.multivariate){ + if(hill.multivariate) { ofile->printField("multivariate","true"); double lower = sqrt(1./hill.sigma[0]); ofile->printField("sigma_"+getPntrToArgument(iarg)->getName()+"_"+ - getPntrToArgument(iarg)->getName(),lower); + getPntrToArgument(iarg)->getName(),lower); } else { ofile->printField("multivariate","false"); ofile->printField("sigma_"+getPntrToArgument(iarg)->getName(),hill.sigma[0]); } double height=hill.height; - if(welltemp_) height *= biasf_/(biasf_-1.0); + if(welltemp_) height *= biasf_/(biasf_-1.0); ofile->printField("height",height); ofile->printField("biasf",biasf_); if(mw_n_>1) ofile->printField("clock",int(std::time(0))); @@ -833,128 +835,128 @@ void PBMetaD::writeGaussian(unsigned iarg, const Gaussian& hill, OFile *ofile) void PBMetaD::addGaussian(unsigned iarg, const Gaussian& hill) { - if(!grid_){hills_[iarg].push_back(hill);} - else{ - vector<unsigned> nneighb=getGaussianSupport(iarg, hill); - vector<Grid::index_t> neighbors=BiasGrids_[iarg]->getNeighbors(hill.center,nneighb); - vector<double> der(1); - vector<double> xx(1); - if(comm.Get_size()==1){ - for(unsigned i=0;i<neighbors.size();++i){ - Grid::index_t ineigh=neighbors[i]; - der[0]=0.0; - BiasGrids_[iarg]->getPoint(ineigh,xx); - double bias=evaluateGaussian(iarg,xx,hill,&der[0]); - BiasGrids_[iarg]->addValueAndDerivatives(ineigh,bias,der); - } - } else { - unsigned stride=comm.Get_size(); - unsigned rank=comm.Get_rank(); - vector<double> allder(neighbors.size(),0.0); - vector<double> allbias(neighbors.size(),0.0); - for(unsigned i=rank;i<neighbors.size();i+=stride){ - Grid::index_t ineigh=neighbors[i]; - BiasGrids_[iarg]->getPoint(ineigh,xx); - allbias[i]=evaluateGaussian(iarg,xx,hill,&allder[i]); - } - comm.Sum(allbias); - comm.Sum(allder); - for(unsigned i=0;i<neighbors.size();++i){ - Grid::index_t ineigh=neighbors[i]; - der[0]=allder[i]; - BiasGrids_[iarg]->addValueAndDerivatives(ineigh,allbias[i],der); + if(!grid_) {hills_[iarg].push_back(hill);} + else { + vector<unsigned> nneighb=getGaussianSupport(iarg, hill); + vector<Grid::index_t> neighbors=BiasGrids_[iarg]->getNeighbors(hill.center,nneighb); + vector<double> der(1); + vector<double> xx(1); + if(comm.Get_size()==1) { + for(unsigned i=0; i<neighbors.size(); ++i) { + Grid::index_t ineigh=neighbors[i]; + der[0]=0.0; + BiasGrids_[iarg]->getPoint(ineigh,xx); + double bias=evaluateGaussian(iarg,xx,hill,&der[0]); + BiasGrids_[iarg]->addValueAndDerivatives(ineigh,bias,der); + } + } else { + unsigned stride=comm.Get_size(); + unsigned rank=comm.Get_rank(); + vector<double> allder(neighbors.size(),0.0); + vector<double> allbias(neighbors.size(),0.0); + for(unsigned i=rank; i<neighbors.size(); i+=stride) { + Grid::index_t ineigh=neighbors[i]; + BiasGrids_[iarg]->getPoint(ineigh,xx); + allbias[i]=evaluateGaussian(iarg,xx,hill,&allder[i]); + } + comm.Sum(allbias); + comm.Sum(allder); + for(unsigned i=0; i<neighbors.size(); ++i) { + Grid::index_t ineigh=neighbors[i]; + der[0]=allder[i]; + BiasGrids_[iarg]->addValueAndDerivatives(ineigh,allbias[i],der); + } } } - } } vector<unsigned> PBMetaD::getGaussianSupport(unsigned iarg, const Gaussian& hill) { - vector<unsigned> nneigh; - double cutoff; - if(hill.multivariate){ - double maxautoval=1./hill.sigma[0]; - cutoff=sqrt(2.0*DP2CUTOFF*maxautoval); - } else { - cutoff=sqrt(2.0*DP2CUTOFF)*hill.sigma[0]; - } - - if(doInt_[iarg]){ - if(hill.center[0]+cutoff > uppI_[iarg] || hill.center[0]-cutoff < lowI_[iarg]) { - // in this case, we updated the entire grid to avoid problems - return BiasGrids_[iarg]->getNbin(); - } else { - nneigh.push_back( static_cast<unsigned>(ceil(cutoff/BiasGrids_[iarg]->getDx()[0]))); - return nneigh; - } - } - - nneigh.push_back( static_cast<unsigned>(ceil(cutoff/BiasGrids_[iarg]->getDx()[0])) ); - - return nneigh; + vector<unsigned> nneigh; + double cutoff; + if(hill.multivariate) { + double maxautoval=1./hill.sigma[0]; + cutoff=sqrt(2.0*DP2CUTOFF*maxautoval); + } else { + cutoff=sqrt(2.0*DP2CUTOFF)*hill.sigma[0]; + } + + if(doInt_[iarg]) { + if(hill.center[0]+cutoff > uppI_[iarg] || hill.center[0]-cutoff < lowI_[iarg]) { + // in this case, we updated the entire grid to avoid problems + return BiasGrids_[iarg]->getNbin(); + } else { + nneigh.push_back( static_cast<unsigned>(ceil(cutoff/BiasGrids_[iarg]->getDx()[0]))); + return nneigh; + } + } + + nneigh.push_back( static_cast<unsigned>(ceil(cutoff/BiasGrids_[iarg]->getDx()[0])) ); + + return nneigh; } double PBMetaD::getBiasAndDerivatives(unsigned iarg, const vector<double>& cv, double* der) { - double bias=0.0; - if(!grid_){ - unsigned stride=comm.Get_size(); - unsigned rank=comm.Get_rank(); - for(unsigned i=rank;i<hills_[iarg].size();i+=stride){ - bias += evaluateGaussian(iarg,cv,hills_[iarg][i],der); - } - comm.Sum(bias); - if(der) comm.Sum(der,1); - }else{ - if(der){ - vector<double> vder(1); - bias = BiasGrids_[iarg]->getValueAndDerivatives(cv,vder); - der[0] = vder[0]; - }else{ - bias = BiasGrids_[iarg]->getValue(cv); - } - } - - return bias; + double bias=0.0; + if(!grid_) { + unsigned stride=comm.Get_size(); + unsigned rank=comm.Get_rank(); + for(unsigned i=rank; i<hills_[iarg].size(); i+=stride) { + bias += evaluateGaussian(iarg,cv,hills_[iarg][i],der); + } + comm.Sum(bias); + if(der) comm.Sum(der,1); + } else { + if(der) { + vector<double> vder(1); + bias = BiasGrids_[iarg]->getValueAndDerivatives(cv,vder); + der[0] = vder[0]; + } else { + bias = BiasGrids_[iarg]->getValue(cv); + } + } + + return bias; } double PBMetaD::evaluateGaussian(unsigned iarg, const vector<double>& cv, const Gaussian& hill, double* der) { - double bias=0.0; - // I use a pointer here because cv is const (and should be const) - // but when using doInt it is easier to locally replace cv[0] with - // the upper/lower limit in case it is out of range - const double *pcv=NULL; - double tmpcv[1]; // tmp array with cv (to be used with doInt_) - tmpcv[0]=cv[0]; - bool isOutOfInt = false; - if(doInt_[iarg]){ - if(cv[0]<lowI_[iarg]) { tmpcv[0]=lowI_[iarg]; isOutOfInt = true; } - else if(cv[0]>uppI_[iarg]) { tmpcv[0]=uppI_[iarg]; isOutOfInt = true; } - } - pcv=&(tmpcv[0]); - - if(hill.multivariate){ - double dp = difference(iarg, hill.center[0], pcv[0]); - double dp2 = 0.5 * dp * dp * hill.sigma[0]; - if(dp2<DP2CUTOFF){ - bias = hill.height*exp(-dp2); - if(der && !isOutOfInt){ - der[0] += -bias * dp * hill.sigma[0]; - } - } - } else { - double dp = difference(iarg, hill.center[0], pcv[0]) * hill.invsigma[0]; - double dp2 = 0.5 * dp * dp; - if(dp2<DP2CUTOFF){ - bias = hill.height*exp(-dp2); - if(der && !isOutOfInt){ - der[0] += -bias * dp * hill.invsigma[0]; - } - } - } - - return bias; + double bias=0.0; +// I use a pointer here because cv is const (and should be const) +// but when using doInt it is easier to locally replace cv[0] with +// the upper/lower limit in case it is out of range + const double *pcv=NULL; + double tmpcv[1]; // tmp array with cv (to be used with doInt_) + tmpcv[0]=cv[0]; + bool isOutOfInt = false; + if(doInt_[iarg]) { + if(cv[0]<lowI_[iarg]) { tmpcv[0]=lowI_[iarg]; isOutOfInt = true; } + else if(cv[0]>uppI_[iarg]) { tmpcv[0]=uppI_[iarg]; isOutOfInt = true; } + } + pcv=&(tmpcv[0]); + + if(hill.multivariate) { + double dp = difference(iarg, hill.center[0], pcv[0]); + double dp2 = 0.5 * dp * dp * hill.sigma[0]; + if(dp2<DP2CUTOFF) { + bias = hill.height*exp(-dp2); + if(der && !isOutOfInt) { + der[0] += -bias * dp * hill.sigma[0]; + } + } + } else { + double dp = difference(iarg, hill.center[0], pcv[0]) * hill.invsigma[0]; + double dp2 = 0.5 * dp * dp; + if(dp2<DP2CUTOFF) { + bias = hill.height*exp(-dp2); + if(der && !isOutOfInt) { + der[0] += -bias * dp * hill.invsigma[0]; + } + } + } + + return bias; } void PBMetaD::calculate() @@ -970,20 +972,20 @@ void PBMetaD::calculate() double ncv = (double) getNumberOfArguments(); double bmin = 1.0e+19; - for(unsigned i=0; i<getNumberOfArguments(); ++i){ - cv[0] = getArgument(i); - der[0] = 0.0; - bias[i] = getBiasAndDerivatives(i, cv, der); - deriv[i] = der[0]; - if(bias[i] < bmin) bmin = bias[i]; + for(unsigned i=0; i<getNumberOfArguments(); ++i) { + cv[0] = getArgument(i); + der[0] = 0.0; + bias[i] = getBiasAndDerivatives(i, cv, der); + deriv[i] = der[0]; + if(bias[i] < bmin) bmin = bias[i]; } double ene = 0.; - for(unsigned i=0; i<getNumberOfArguments(); ++i){ + for(unsigned i=0; i<getNumberOfArguments(); ++i) { ene += exp((-bias[i]+bmin)/kbt_); } - - // set Forces - for(unsigned i=0; i<getNumberOfArguments(); ++i){ + + // set Forces + for(unsigned i=0; i<getNumberOfArguments(); ++i) { const double f = - exp((-bias[i]+bmin)/kbt_) / (ene) * deriv[i]; setOutputForce(i, f); } @@ -997,129 +999,129 @@ void PBMetaD::update() { bool multivariate; // adding hills criteria - bool nowAddAHill; - if(getStep()%stride_==0 && !isFirstStep) nowAddAHill=true; + bool nowAddAHill; + if(getStep()%stride_==0 && !isFirstStep) nowAddAHill=true; else { nowAddAHill=false; isFirstStep=false; } - // if you use adaptive, call the FlexibleBin - if(adaptive_!=FlexibleBin::none){ - for(unsigned i=0;i<getNumberOfArguments();i++) flexbin[i].update(nowAddAHill,i); + // if you use adaptive, call the FlexibleBin + if(adaptive_!=FlexibleBin::none) { + for(unsigned i=0; i<getNumberOfArguments(); i++) flexbin[i].update(nowAddAHill,i); multivariate=true; } else { multivariate=false; } - if(nowAddAHill){ - // get all biases and heights - vector<double> cv(getNumberOfArguments()); - vector<double> bias(getNumberOfArguments()); - vector<double> thissigma(getNumberOfArguments()); - vector<double> height(getNumberOfArguments()); - vector<double> cv_tmp(1); - vector<double> sigma_tmp(1); - double norm = 0.0; - double bmin = 1.0e+19; - for(unsigned i=0; i<getNumberOfArguments(); ++i){ - if(adaptive_!=FlexibleBin::none) thissigma[i]=flexbin[i].getInverseMatrix(i)[0]; - else thissigma[i]=sigma0_[i]; - cv[i] = getArgument(i); - cv_tmp[0] = getArgument(i); - bias[i] = getBiasAndDerivatives(i, cv_tmp); - if(bias[i] < bmin) bmin = bias[i]; - } - // calculate heights and norm - for(unsigned i=0; i<getNumberOfArguments(); ++i){ - double h = exp((-bias[i]+bmin)/kbt_); - norm += h; - height[i] = h; - } - // normalize and apply welltemp correction - for(unsigned i=0; i<getNumberOfArguments(); ++i){ - height[i] *= height0_ / norm; - if(welltemp_) height[i] *= exp(-bias[i]/(kbt_*(biasf_-1.0))); - } - - // MPI Multiple walkers: share hills and add them all - if(walkers_mpi){ - // Allocate arrays to store all walkers hills - std::vector<double> all_cv(mpi_nw_*cv.size(), 0.0); - std::vector<double> all_sigma(mpi_nw_*getNumberOfArguments(), 0.0); - std::vector<double> all_height(mpi_nw_*height.size(), 0.0); - if(comm.Get_rank()==0){ - // fill in value - for(unsigned i=0; i<getNumberOfArguments(); ++i){ - unsigned j = mpi_id_ * getNumberOfArguments() + i; - all_cv[j] = cv[i]; - all_sigma[j] = thissigma[i]; - all_height[j] = height[i]; - } - // Communicate (only root) - multi_sim_comm.Sum(&all_cv[0], all_cv.size()); - multi_sim_comm.Sum(&all_sigma[0], all_sigma.size()); - multi_sim_comm.Sum(&all_height[0], all_height.size()); - } - // Share info with group members - comm.Sum(&all_cv[0], all_cv.size()); - comm.Sum(&all_sigma[0], all_sigma.size()); - comm.Sum(&all_height[0], all_height.size()); - // now add hills one by one - for(unsigned j=0; j<mpi_nw_; ++j){ - for(unsigned i=0; i<getNumberOfArguments(); ++i){ - cv_tmp[0] = all_cv[j*cv.size()+i]; - double height_tmp = all_height[j*cv.size()+i]; - sigma_tmp[0] = all_sigma[j*cv.size()+i]; - Gaussian newhill = Gaussian(cv_tmp, sigma_tmp, height_tmp, multivariate); - addGaussian(i, newhill); - writeGaussian(i, newhill, hillsOfiles_[i]); + if(nowAddAHill) { + // get all biases and heights + vector<double> cv(getNumberOfArguments()); + vector<double> bias(getNumberOfArguments()); + vector<double> thissigma(getNumberOfArguments()); + vector<double> height(getNumberOfArguments()); + vector<double> cv_tmp(1); + vector<double> sigma_tmp(1); + double norm = 0.0; + double bmin = 1.0e+19; + for(unsigned i=0; i<getNumberOfArguments(); ++i) { + if(adaptive_!=FlexibleBin::none) thissigma[i]=flexbin[i].getInverseMatrix(i)[0]; + else thissigma[i]=sigma0_[i]; + cv[i] = getArgument(i); + cv_tmp[0] = getArgument(i); + bias[i] = getBiasAndDerivatives(i, cv_tmp); + if(bias[i] < bmin) bmin = bias[i]; + } + // calculate heights and norm + for(unsigned i=0; i<getNumberOfArguments(); ++i) { + double h = exp((-bias[i]+bmin)/kbt_); + norm += h; + height[i] = h; + } + // normalize and apply welltemp correction + for(unsigned i=0; i<getNumberOfArguments(); ++i) { + height[i] *= height0_ / norm; + if(welltemp_) height[i] *= exp(-bias[i]/(kbt_*(biasf_-1.0))); + } + + // MPI Multiple walkers: share hills and add them all + if(walkers_mpi) { + // Allocate arrays to store all walkers hills + std::vector<double> all_cv(mpi_nw_*cv.size(), 0.0); + std::vector<double> all_sigma(mpi_nw_*getNumberOfArguments(), 0.0); + std::vector<double> all_height(mpi_nw_*height.size(), 0.0); + if(comm.Get_rank()==0) { + // fill in value + for(unsigned i=0; i<getNumberOfArguments(); ++i) { + unsigned j = mpi_id_ * getNumberOfArguments() + i; + all_cv[j] = cv[i]; + all_sigma[j] = thissigma[i]; + all_height[j] = height[i]; + } + // Communicate (only root) + multi_sim_comm.Sum(&all_cv[0], all_cv.size()); + multi_sim_comm.Sum(&all_sigma[0], all_sigma.size()); + multi_sim_comm.Sum(&all_height[0], all_height.size()); } - } - // just add your own hills - }else{ - for(unsigned i=0; i<getNumberOfArguments(); ++i){ - cv_tmp[0] = cv[i]; - if(adaptive_!=FlexibleBin::none) sigma_tmp[0]=thissigma[i]; - else sigma_tmp[0] = sigma0_[i]; - Gaussian newhill = Gaussian(cv_tmp, sigma_tmp, height[i], multivariate); - addGaussian(i, newhill); - writeGaussian(i, newhill, hillsOfiles_[i]); - } - } + // Share info with group members + comm.Sum(&all_cv[0], all_cv.size()); + comm.Sum(&all_sigma[0], all_sigma.size()); + comm.Sum(&all_height[0], all_height.size()); + // now add hills one by one + for(unsigned j=0; j<mpi_nw_; ++j) { + for(unsigned i=0; i<getNumberOfArguments(); ++i) { + cv_tmp[0] = all_cv[j*cv.size()+i]; + double height_tmp = all_height[j*cv.size()+i]; + sigma_tmp[0] = all_sigma[j*cv.size()+i]; + Gaussian newhill = Gaussian(cv_tmp, sigma_tmp, height_tmp, multivariate); + addGaussian(i, newhill); + writeGaussian(i, newhill, hillsOfiles_[i]); + } + } + // just add your own hills + } else { + for(unsigned i=0; i<getNumberOfArguments(); ++i) { + cv_tmp[0] = cv[i]; + if(adaptive_!=FlexibleBin::none) sigma_tmp[0]=thissigma[i]; + else sigma_tmp[0] = sigma0_[i]; + Gaussian newhill = Gaussian(cv_tmp, sigma_tmp, height[i], multivariate); + addGaussian(i, newhill); + writeGaussian(i, newhill, hillsOfiles_[i]); + } + } } - // write grid files - if(wgridstride_>0 && (getStep()%wgridstride_==0 || getCPT())) { - int r = 0; - if(walkers_mpi) { - if(comm.Get_rank()==0) r=multi_sim_comm.Get_rank(); - comm.Bcast(r,0); - } - if(r==0) { - for(unsigned i=0; i<gridfiles_.size(); ++i) { - gridfiles_[i]->rewind(); - BiasGrids_[i]->writeToFile(*gridfiles_[i]); - gridfiles_[i]->flush(); - } - } - } + // write grid files + if(wgridstride_>0 && (getStep()%wgridstride_==0 || getCPT())) { + int r = 0; + if(walkers_mpi) { + if(comm.Get_rank()==0) r=multi_sim_comm.Get_rank(); + comm.Bcast(r,0); + } + if(r==0) { + for(unsigned i=0; i<gridfiles_.size(); ++i) { + gridfiles_[i]->rewind(); + BiasGrids_[i]->writeToFile(*gridfiles_[i]); + gridfiles_[i]->flush(); + } + } + } // if multiple walkers and time to read Gaussians - if(mw_n_>1 && getStep()%mw_rstride_==0){ - for(int j=0;j<mw_n_;++j){ - for(unsigned i=0;i<hillsfname.size();++i){ + if(mw_n_>1 && getStep()%mw_rstride_==0) { + for(int j=0; j<mw_n_; ++j) { + for(unsigned i=0; i<hillsfname.size(); ++i) { unsigned k=j*hillsfname.size()+i; // don't read your own Gaussians if(j==mw_id_) continue; - // if the file is not open yet - if(!(ifiles[k]->isOpen())){ + // if the file is not open yet + if(!(ifiles[k]->isOpen())) { // check if it exists now and open it! if(ifiles[k]->FileExist(ifilesnames[k])) { ifiles[k]->open(ifilesnames[k]); ifiles[k]->reset(false); } - // otherwise read the new Gaussians + // otherwise read the new Gaussians } else { log.printf(" Reading hills from %s:",ifilesnames[k].c_str()); readGaussians(i,ifiles[k]); @@ -1131,21 +1133,21 @@ void PBMetaD::update() } -/// takes a pointer to the file and a template string with values v and gives back the next center, sigma and height +/// takes a pointer to the file and a template string with values v and gives back the next center, sigma and height bool PBMetaD::scanOneHill(unsigned iarg, IFile *ifile, vector<Value> &tmpvalues, vector<double> ¢er, vector<double> &sigma, double &height, bool &multivariate) { double dummy; multivariate=false; - if(ifile->scanField("time",dummy)){ + if(ifile->scanField("time",dummy)) { ifile->scanField( &tmpvalues[0] ); - if( tmpvalues[0].isPeriodic() && ! getPntrToArgument(iarg)->isPeriodic() ){ - error("in hills file periodicity for variable " + tmpvalues[0].getName() + " does not match periodicity in input"); - } else if( tmpvalues[0].isPeriodic() ){ - std::string imin, imax; tmpvalues[0].getDomain( imin, imax ); - std::string rmin, rmax; getPntrToArgument(iarg)->getDomain( rmin, rmax ); - if( imin!=rmin || imax!=rmax ){ - error("in hills file periodicity for variable " + tmpvalues[0].getName() + " does not match periodicity in input"); - } + if( tmpvalues[0].isPeriodic() && ! getPntrToArgument(iarg)->isPeriodic() ) { + error("in hills file periodicity for variable " + tmpvalues[0].getName() + " does not match periodicity in input"); + } else if( tmpvalues[0].isPeriodic() ) { + std::string imin, imax; tmpvalues[0].getDomain( imin, imax ); + std::string rmin, rmax; getPntrToArgument(iarg)->getDomain( rmin, rmax ); + if( imin!=rmin || imax!=rmax ) { + error("in hills file periodicity for variable " + tmpvalues[0].getName() + " does not match periodicity in input"); + } } center[0]=tmpvalues[0].get(); std::string sss; @@ -1154,9 +1156,9 @@ bool PBMetaD::scanOneHill(unsigned iarg, IFile *ifile, vector<Value> &tmpvalues, else if(sss=="false") multivariate=false; else plumed_merror("cannot parse multivariate = "+ sss); - if(multivariate){ + if(multivariate) { ifile->scanField("sigma_"+getPntrToArgument(iarg)->getName()+"_"+ - getPntrToArgument(iarg)->getName(),sigma[0]); + getPntrToArgument(iarg)->getName(),sigma[0]); sigma[0] = 1./(sigma[0]*sigma[0]); } else { ifile->scanField("sigma_"+getPntrToArgument(iarg)->getName(),sigma[0]); @@ -1168,9 +1170,9 @@ bool PBMetaD::scanOneHill(unsigned iarg, IFile *ifile, vector<Value> &tmpvalues, if(ifile->FieldExist("upper_int")) ifile->scanField("upper_int",dummy); ifile->scanField(); return true; - } else { - return false; - } + } else { + return false; + } } } diff --git a/src/bias/Restraint.cpp b/src/bias/Restraint.cpp index fc3606820..8bb3df202 100644 --- a/src/bias/Restraint.cpp +++ b/src/bias/Restraint.cpp @@ -26,16 +26,16 @@ using namespace std; -namespace PLMD{ -namespace bias{ +namespace PLMD { +namespace bias { //+PLUMEDOC BIAS RESTRAINT /* -Adds harmonic and/or linear restraints on one or more variables. +Adds harmonic and/or linear restraints on one or more variables. Either or both of SLOPE and KAPPA must be present to specify the linear and harmonic force constants -respectively. The resulting potential is given by: +respectively. The resulting potential is given by: \f[ \sum_i \frac{k_i}{2} (x_i-a_i)^2 + m_i*(x_i-a_i) \f]. @@ -43,7 +43,7 @@ respectively. The resulting potential is given by: The number of components for any vector of force constants must be equal to the number of arguments to the action. -Additional material and examples can be also found in the tutorial \ref belfast-4 +Additional material and examples can be also found in the tutorial \ref belfast-4 \par Examples The following input tells plumed to restrain the distance between atoms 3 and 5 @@ -60,7 +60,7 @@ PRINT ARG=restraint.bias */ //+ENDPLUMEDOC -class Restraint : public Bias{ +class Restraint : public Bias { std::vector<double> at; std::vector<double> kappa; std::vector<double> slope; @@ -73,20 +73,20 @@ public: PLUMED_REGISTER_ACTION(Restraint,"RESTRAINT") -void Restraint::registerKeywords(Keywords& keys){ - Bias::registerKeywords(keys); - keys.use("ARG"); - keys.add("compulsory","SLOPE","0.0","specifies that the restraint is linear and what the values of the force constants on each of the variables are"); - keys.add("compulsory","KAPPA","0.0","specifies that the restraint is harmonic and what the values of the force constants on each of the variables are"); - keys.add("compulsory","AT","the position of the restraint"); - keys.addOutputComponent("force2","default","the instantaneous value of the squared force due to this bias potential"); +void Restraint::registerKeywords(Keywords& keys) { + Bias::registerKeywords(keys); + keys.use("ARG"); + keys.add("compulsory","SLOPE","0.0","specifies that the restraint is linear and what the values of the force constants on each of the variables are"); + keys.add("compulsory","KAPPA","0.0","specifies that the restraint is harmonic and what the values of the force constants on each of the variables are"); + keys.add("compulsory","AT","the position of the restraint"); + keys.addOutputComponent("force2","default","the instantaneous value of the squared force due to this bias potential"); } Restraint::Restraint(const ActionOptions&ao): -PLUMED_BIAS_INIT(ao), -at(getNumberOfArguments()), -kappa(getNumberOfArguments(),0.0), -slope(getNumberOfArguments(),0.0) + PLUMED_BIAS_INIT(ao), + at(getNumberOfArguments()), + kappa(getNumberOfArguments(),0.0), + slope(getNumberOfArguments(),0.0) { parseVector("SLOPE",slope); parseVector("KAPPA",kappa); @@ -94,13 +94,13 @@ slope(getNumberOfArguments(),0.0) checkRead(); log.printf(" at"); - for(unsigned i=0;i<at.size();i++) log.printf(" %f",at[i]); + for(unsigned i=0; i<at.size(); i++) log.printf(" %f",at[i]); log.printf("\n"); log.printf(" with harmonic force constant"); - for(unsigned i=0;i<kappa.size();i++) log.printf(" %f",kappa[i]); + for(unsigned i=0; i<kappa.size(); i++) log.printf(" %f",kappa[i]); log.printf("\n"); log.printf(" and linear force constant"); - for(unsigned i=0;i<slope.size();i++) log.printf(" %f",slope[i]); + for(unsigned i=0; i<slope.size(); i++) log.printf(" %f",slope[i]); log.printf("\n"); addComponent("force2"); @@ -109,10 +109,10 @@ slope(getNumberOfArguments(),0.0) } -void Restraint::calculate(){ +void Restraint::calculate() { double ene=0.0; double totf2=0.0; - for(unsigned i=0;i<getNumberOfArguments();++i){ + for(unsigned i=0; i<getNumberOfArguments(); ++i) { const double cv=difference(i,at[i],getArgument(i)); const double k=kappa[i]; const double m=slope[i]; diff --git a/src/bias/ReweightBase.cpp b/src/bias/ReweightBase.cpp index 671305476..bfb5ddede 100644 --- a/src/bias/ReweightBase.cpp +++ b/src/bias/ReweightBase.cpp @@ -26,7 +26,7 @@ namespace PLMD { namespace bias { -void ReweightBase::registerKeywords(Keywords& keys){ +void ReweightBase::registerKeywords(Keywords& keys) { Action::registerKeywords( keys ); ActionWithValue::registerKeywords( keys ); ActionWithArguments::registerKeywords( keys ); @@ -36,19 +36,19 @@ void ReweightBase::registerKeywords(Keywords& keys){ } ReweightBase::ReweightBase(const ActionOptions&ao): -Action(ao), -ActionWithValue(ao), -ActionWithArguments(ao) + Action(ao), + ActionWithValue(ao), + ActionWithArguments(ao) { - simtemp=0.; parse("TEMP",simtemp); - if(simtemp>0) simtemp*=plumed.getAtoms().getKBoltzmann(); - else simtemp=plumed.getAtoms().getKbT(); - if(simtemp==0) error("The MD engine does not pass the temperature to plumed so you have to specify it using TEMP"); - // Create something to hold the weight - addValue(); setNotPeriodic(); + simtemp=0.; parse("TEMP",simtemp); + if(simtemp>0) simtemp*=plumed.getAtoms().getKBoltzmann(); + else simtemp=plumed.getAtoms().getKbT(); + if(simtemp==0) error("The MD engine does not pass the temperature to plumed so you have to specify it using TEMP"); + // Create something to hold the weight + addValue(); setNotPeriodic(); } -void ReweightBase::calculate(){ +void ReweightBase::calculate() { double weight = getLogWeight(); setValue( weight ); } diff --git a/src/bias/ReweightBase.h b/src/bias/ReweightBase.h index e3dfd35ad..f39e94d70 100644 --- a/src/bias/ReweightBase.h +++ b/src/bias/ReweightBase.h @@ -28,9 +28,9 @@ namespace PLMD { namespace bias { -class ReweightBase : -public ActionWithValue, -public ActionWithArguments +class ReweightBase : + public ActionWithValue, + public ActionWithArguments { protected: /// The temperature at which you are running the simulation @@ -38,11 +38,11 @@ protected: public: static void registerKeywords(Keywords&); explicit ReweightBase(const ActionOptions&ao); - unsigned getNumberOfDerivatives(){ return 0; } + unsigned getNumberOfDerivatives() { return 0; } void calculate(); virtual double getLogWeight() const = 0; - void apply(){} -}; + void apply() {} +}; } } diff --git a/src/bias/ReweightBias.cpp b/src/bias/ReweightBias.cpp index d5459df96..d0b2d90a3 100644 --- a/src/bias/ReweightBias.cpp +++ b/src/bias/ReweightBias.cpp @@ -26,24 +26,24 @@ /* Calculate weights for ensemble averages that negate the effect the bias has on the region of phase space explored -If a static or pseudo-static bias \f$V(x,t')\f$ is acting on +If a static or pseudo-static bias \f$V(x,t')\f$ is acting on the system we can remove the bias and get the unbiased probability distribution using: \f[ -\langle P(s',t) \rangle = \frac{ \sum_{t'}^t \delta( s(x) - s' ) \exp\left( +\frac{V(x,t')}{k_B T} \right) }{ \sum_t'^t \exp\left( +\frac{V(x,t')}{k_B T} \right) } +\langle P(s',t) \rangle = \frac{ \sum_{t'}^t \delta( s(x) - s' ) \exp\left( +\frac{V(x,t')}{k_B T} \right) }{ \sum_t'^t \exp\left( +\frac{V(x,t')}{k_B T} \right) } \f] -The weights calculated by this action are equal to \f$\exp\left( +\frac{V(x,t')}{k_B T} \right)\f$ these weights can then be used in any action -that computes ensemble averages. For example this action can be used in tandem with \ref HISTOGRAM or \ref AVERAGE. +The weights calculated by this action are equal to \f$\exp\left( +\frac{V(x,t')}{k_B T} \right)\f$ these weights can then be used in any action +that computes ensemble averages. For example this action can be used in tandem with \ref HISTOGRAM or \ref AVERAGE. \par Examples -In the following example there is a fixed restraint on the distance between atoms 1 and 2. Clearly, this +In the following example there is a fixed restraint on the distance between atoms 1 and 2. Clearly, this restraint will have an effect on the region of phase space that will be sampled when an MD simulation is run using this variable. Consequently, when the histogram as a function of the distance, \f$x\f$, is accumulated, we use reweighting into order to discount the effect of the bias from our final histogram. -\verbatim +\verbatim x: DISTANCE ATOMS=1,2 RESTRAINT ARG=x SLOPE=1.0 AT=0.0 as: REWEIGHT_BIAS TEMP=300 @@ -77,21 +77,21 @@ public: PLUMED_REGISTER_ACTION(ReweightBias,"REWEIGHT_BIAS") -void ReweightBias::registerKeywords(Keywords& keys ){ +void ReweightBias::registerKeywords(Keywords& keys ) { ReweightBase::registerKeywords( keys ); keys.remove("ARG"); keys.add("compulsory","ARG","*.bias","the biases that must be taken into account when reweighting"); } ReweightBias::ReweightBias(const ActionOptions&ao): -Action(ao), -ReweightBase(ao) + Action(ao), + ReweightBase(ao) { } double ReweightBias::getLogWeight() const { - // Retrieve the bias - double bias=0.0; for(unsigned i=0;i<getNumberOfArguments();++i) bias+=getArgument(i); - return bias / simtemp; + // Retrieve the bias + double bias=0.0; for(unsigned i=0; i<getNumberOfArguments(); ++i) bias+=getArgument(i); + return bias / simtemp; } } diff --git a/src/bias/ReweightMetad.cpp b/src/bias/ReweightMetad.cpp index e53170be7..766ed40df 100644 --- a/src/bias/ReweightMetad.cpp +++ b/src/bias/ReweightMetad.cpp @@ -31,18 +31,18 @@ of the configurations visited during a metadynamics simulation. \par Examples -In the following example there is a metadynamics bias acting on the distance between atoms 1 and 2. Clearly, this +In the following example there is a metadynamics bias acting on the distance between atoms 1 and 2. Clearly, this bias will have an effect on the region of phase space that will be sampled when an MD simulation is run using this variable. Consequently, when the histogram as a function of the angle, \f$a\f$, is accumulated, -we use reweighting into order to discount the effect of the bias from our final histogram. We do not use -\ref REWEIGHT_BIAS here, however, as the bias changes with time. We thus use the reweighting algorithm for +we use reweighting into order to discount the effect of the bias from our final histogram. We do not use +\ref REWEIGHT_BIAS here, however, as the bias changes with time. We thus use the reweighting algorithm for metadynamics instead. Notice also that we have to specify how often we would like to calculate the c(t) reweighting factor and the grid over which we calculate c(t) in the input to the METAD command. \verbatim a: ANGLE ATOMS=1,2,3 x: DISTANCE ATOMS=1,2 -METAD ARG=x PACE=100 SIGMA=0.1 HEIGHT=1.5 BIASFACTOR=5 GRID_MIN=0 GRID_MAX=10 GRID_BIN=100 REWEIGHTING_NGRID=100 REWEIGHTING_NHILLS=50 +METAD ARG=x PACE=100 SIGMA=0.1 HEIGHT=1.5 BIASFACTOR=5 GRID_MIN=0 GRID_MAX=10 GRID_BIN=100 REWEIGHTING_NGRID=100 REWEIGHTING_NHILLS=50 as: REWEIGHT_METAD TEMP=300 @@ -75,21 +75,21 @@ public: PLUMED_REGISTER_ACTION(ReweightMetad,"REWEIGHT_METAD") -void ReweightMetad::registerKeywords(Keywords& keys ){ +void ReweightMetad::registerKeywords(Keywords& keys ) { ReweightBase::registerKeywords( keys ); keys.remove("ARG"); - keys.add("compulsory","ARG","*.rbias","the biases that must be taken into account when reweighting"); + keys.add("compulsory","ARG","*.rbias","the biases that must be taken into account when reweighting"); } ReweightMetad::ReweightMetad(const ActionOptions&ao): -Action(ao), -ReweightBase(ao) + Action(ao), + ReweightBase(ao) { } double ReweightMetad::getLogWeight() const { - // Retrieve the bias - double bias=0.0; for(unsigned i=0;i<getNumberOfArguments();++i) bias+=getArgument(i); - return bias / simtemp; + // Retrieve the bias + double bias=0.0; for(unsigned i=0; i<getNumberOfArguments(); ++i) bias+=getArgument(i); + return bias / simtemp; } } diff --git a/src/bias/ReweightTemperature.cpp b/src/bias/ReweightTemperature.cpp index f11cf54d4..203d4930e 100644 --- a/src/bias/ReweightTemperature.cpp +++ b/src/bias/ReweightTemperature.cpp @@ -30,29 +30,29 @@ Calculate weights for ensemble averages allow for the computing of ensemble averages at temperatures lower/higher than that used in your original simulation. We can use our knowledge of the Boltzmann distribution in the cannonical ensemble to reweight the data -contained in trajectories. Using this procedure we can take trajectory at temperature \f$T_1\f$ and use it to +contained in trajectories. Using this procedure we can take trajectory at temperature \f$T_1\f$ and use it to extract probabilities at a different temperature, \f$T_2\f$, using: \f[ P(s',t) = \frac{ \sum_{t'}^t \delta( s(x) - s' ) \exp\left( +( \left[\frac{1}{T_1} - \frac{1}{T_2}\right] \frac{U(x,t')}{k_B} \right) }{ \sum_{t'}^t \exp\left( +\left[\frac{1}{T_1} - \frac{1}{T_2}\right] \frac{U(x,t')}{k_B} \right) } \f] -The weights calculated by this action are equal to \f$\exp\left( +( \left[\frac{1}{T_1} - \frac{1}{T_2}\right] \frac{U(x,t')}{k_B} \right)\f$ and take -the effect the bias has on the system into account. These weights can be used in any action -that computes ensemble averages. For example this action can be used in tandem with \ref HISTOGRAM or \ref AVERAGE. +The weights calculated by this action are equal to \f$\exp\left( +( \left[\frac{1}{T_1} - \frac{1}{T_2}\right] \frac{U(x,t')}{k_B} \right)\f$ and take +the effect the bias has on the system into account. These weights can be used in any action +that computes ensemble averages. For example this action can be used in tandem with \ref HISTOGRAM or \ref AVERAGE. \par Examples The following input can be used to postprocess a molecular dynamics trajectory calculated at a temperature of 500 K. -The \ref HISTOGRAM as a function of the distance between atoms 1 and 2 that would have been obtained if the simulation +The \ref HISTOGRAM as a function of the distance between atoms 1 and 2 that would have been obtained if the simulation had been run at the lower temperature of 300 K is estimated using the data from the higher temperature trajectory and output to a file. \verbatim -x: DISTANCE ATOMS=1,2 +x: DISTANCE ATOMS=1,2 aa: REWEIGHT_TEMP TEMP=500 REWEIGHT_TEMP=300 hB: HISTOGRAM ARG=x GRID_MIN=0.0 GRID_MAX=3.0 GRID_BIN=100 BANDWIDTH=0.1 LOGWEIGHTS=aa -DUMPGRID GRID=hB FILE=histoB +DUMPGRID GRID=hB FILE=histoB \endverbatim */ @@ -76,42 +76,42 @@ public: PLUMED_REGISTER_ACTION(ReweightTemperature,"REWEIGHT_TEMP") -void ReweightTemperature::registerKeywords(Keywords& keys ){ +void ReweightTemperature::registerKeywords(Keywords& keys ) { ReweightBase::registerKeywords( keys ); keys.add("compulsory","REWEIGHT_TEMP","reweight data from a trajectory at one temperature and output the probability " - "distribution at a second temperature. This is not possible during postprocessing."); + "distribution at a second temperature. This is not possible during postprocessing."); } ReweightTemperature::ReweightTemperature(const ActionOptions&ao): -Action(ao), -ReweightBase(ao) + Action(ao), + ReweightBase(ao) { - parse("REWEIGHT_TEMP",rtemp); - log.printf(" reweighting simulation to probabilities at temperature %f\n",rtemp); - rtemp*=plumed.getAtoms().getKBoltzmann(); - - std::vector<ActionWithValue*> all=plumed.getActionSet().select<ActionWithValue*>(); - if( all.empty() ) error("your input file is not telling plumed to calculate anything"); - log.printf(" using the following biases in reweighting "); - for(unsigned j=0;j<all.size();j++){ - std::string flab; flab=all[j]->getLabel() + ".bias"; - if( all[j]->exists(flab) ){ - biases.push_back( all[j]->copyOutput(flab) ); - log.printf(" %s", flab.c_str()); - } - } - log.printf("\n"); + parse("REWEIGHT_TEMP",rtemp); + log.printf(" reweighting simulation to probabilities at temperature %f\n",rtemp); + rtemp*=plumed.getAtoms().getKBoltzmann(); + + std::vector<ActionWithValue*> all=plumed.getActionSet().select<ActionWithValue*>(); + if( all.empty() ) error("your input file is not telling plumed to calculate anything"); + log.printf(" using the following biases in reweighting "); + for(unsigned j=0; j<all.size(); j++) { + std::string flab; flab=all[j]->getLabel() + ".bias"; + if( all[j]->exists(flab) ) { + biases.push_back( all[j]->copyOutput(flab) ); + log.printf(" %s", flab.c_str()); + } + } + log.printf("\n"); } -void ReweightTemperature::prepare(){ - plumed.getAtoms().setCollectEnergy(true); +void ReweightTemperature::prepare() { + plumed.getAtoms().setCollectEnergy(true); } double ReweightTemperature::getLogWeight() const { - // Retrieve the bias - double bias=0.0; for(unsigned i=0;i<biases.size();++i) bias+=biases[i]->get(); - double energy=plumed.getAtoms().getEnergy()+bias; - return -( (1.0/rtemp) - (1.0/simtemp) )*(energy+bias); + // Retrieve the bias + double bias=0.0; for(unsigned i=0; i<biases.size(); ++i) bias+=biases[i]->get(); + double energy=plumed.getAtoms().getEnergy()+bias; + return -( (1.0/rtemp) - (1.0/simtemp) )*(energy+bias); } } diff --git a/src/bias/UWalls.cpp b/src/bias/UWalls.cpp index 04626b5db..0f096f11b 100644 --- a/src/bias/UWalls.cpp +++ b/src/bias/UWalls.cpp @@ -26,16 +26,16 @@ using namespace std; -namespace PLMD{ -namespace bias{ +namespace PLMD { +namespace bias { //+PLUMEDOC BIAS UPPER_WALLS /* Defines a wall for the value of one or more collective variables, - which limits the region of the phase space accessible during the simulation. + which limits the region of the phase space accessible during the simulation. -The restraining potential starts acting on the system when the value of the CV is greater -(in the case of UPPER_WALLS) or lower (in the case of LOWER_WALLS) than a certain limit \f$a_i\f$ (AT) +The restraining potential starts acting on the system when the value of the CV is greater +(in the case of UPPER_WALLS) or lower (in the case of LOWER_WALLS) than a certain limit \f$a_i\f$ (AT) minus an offset \f$o_i\f$ (OFFSET). The expression for the bias due to the wall is given by: @@ -43,15 +43,15 @@ The expression for the bias due to the wall is given by: \sum_i {k_i}((x_i-a_i+o_i)/s_i)^e_i \f$ -\f$k_i\f$ (KAPPA) is an energy constant in internal unit of the code, \f$s_i\f$ (EPS) a rescaling factor and +\f$k_i\f$ (KAPPA) is an energy constant in internal unit of the code, \f$s_i\f$ (EPS) a rescaling factor and \f$e_i\f$ (EXP) the exponent determining the power law. By default: EXP = 2, EPS = 1.0, OFFSET = 0. \par Examples -The following input tells plumed to add both a lower and an upper walls on the distance +The following input tells plumed to add both a lower and an upper walls on the distance between atoms 3 and 5 and the distance between atoms 2 and 4. The lower and upper limits -are defined at different values. The strength of the walls is the same for the four cases. -It also tells plumed to print the energy of the walls. +are defined at different values. The strength of the walls is the same for the four cases. +It also tells plumed to print the energy of the walls. \verbatim DISTANCE ATOMS=3,5 LABEL=d1 DISTANCE ATOMS=2,4 LABEL=d2 @@ -64,7 +64,7 @@ PRINT ARG=uwall.bias,lwall.bias */ //+ENDPLUMEDOC -class UWalls : public Bias{ +class UWalls : public Bias { std::vector<double> at; std::vector<double> kappa; std::vector<double> exp; @@ -78,7 +78,7 @@ public: PLUMED_REGISTER_ACTION(UWalls,"UPPER_WALLS") -void UWalls::registerKeywords(Keywords& keys){ +void UWalls::registerKeywords(Keywords& keys) { Bias::registerKeywords(keys); keys.use("ARG"); keys.add("compulsory","AT","the positions of the wall. The a_i in the expression for a wall."); @@ -90,12 +90,12 @@ void UWalls::registerKeywords(Keywords& keys){ } UWalls::UWalls(const ActionOptions&ao): -PLUMED_BIAS_INIT(ao), -at(getNumberOfArguments(),0), -kappa(getNumberOfArguments(),0.0), -exp(getNumberOfArguments(),2.0), -eps(getNumberOfArguments(),1.0), -offset(getNumberOfArguments(),0.0) + PLUMED_BIAS_INIT(ao), + at(getNumberOfArguments(),0), + kappa(getNumberOfArguments(),0.0), + exp(getNumberOfArguments(),2.0), + eps(getNumberOfArguments(),1.0), + offset(getNumberOfArguments(),0.0) { // Note : the sizes of these vectors are checked automatically by parseVector parseVector("OFFSET",offset); @@ -106,28 +106,28 @@ offset(getNumberOfArguments(),0.0) checkRead(); log.printf(" at"); - for(unsigned i=0;i<at.size();i++) log.printf(" %f",at[i]); + for(unsigned i=0; i<at.size(); i++) log.printf(" %f",at[i]); log.printf("\n"); log.printf(" with an offset"); - for(unsigned i=0;i<offset.size();i++) log.printf(" %f",offset[i]); + for(unsigned i=0; i<offset.size(); i++) log.printf(" %f",offset[i]); log.printf("\n"); log.printf(" with force constant"); - for(unsigned i=0;i<kappa.size();i++) log.printf(" %f",kappa[i]); + for(unsigned i=0; i<kappa.size(); i++) log.printf(" %f",kappa[i]); log.printf("\n"); log.printf(" and exponent"); - for(unsigned i=0;i<exp.size();i++) log.printf(" %f",exp[i]); + for(unsigned i=0; i<exp.size(); i++) log.printf(" %f",exp[i]); log.printf("\n"); log.printf(" rescaled"); - for(unsigned i=0;i<eps.size();i++) log.printf(" %f",eps[i]); + for(unsigned i=0; i<eps.size(); i++) log.printf(" %f",eps[i]); log.printf("\n"); addComponent("force2"); componentIsNotPeriodic("force2"); } -void UWalls::calculate(){ +void UWalls::calculate() { double ene=0.0; double totf2=0.0; - for(unsigned i=0;i<getNumberOfArguments();++i){ + for(unsigned i=0; i<getNumberOfArguments(); ++i) { const double cv=difference(i,at[i],getArgument(i)); const double k=kappa[i]; const double exponent=exp[i]; diff --git a/src/cltools/CLTool.h b/src/cltools/CLTool.h index 1d81b035d..3d5adbbc5 100644 --- a/src/cltools/CLTool.h +++ b/src/cltools/CLTool.h @@ -22,11 +22,11 @@ #ifndef __PLUMED_cltools_CLTool_h #define __PLUMED_cltools_CLTool_h #include "core/CLTool.h" -namespace PLMD{ -namespace cltools{ +namespace PLMD { +namespace cltools { // Ideally core/CLTool.h should be moved to this directory and CLTool should stay in namespace PLMD::cltools // With this trick, PLMD::CLTool is visible as PLMD::cltools::CLTool - using PLMD::CLTool; +using PLMD::CLTool; } } #endif diff --git a/src/cltools/Driver.cpp b/src/cltools/Driver.cpp index c47d6a2e1..02435ea65 100644 --- a/src/cltools/Driver.cpp +++ b/src/cltools/Driver.cpp @@ -40,7 +40,7 @@ #ifndef __PLUMED_HAS_EXTERNAL_MOLFILE_PLUGINS /* Use the internal ones. Alternatively: * ifeq (,$(findstring __PLUMED_HAS_EXTERNAL_MOLFILE_PLUGINS,$(CPPFLAGS))) - * CPPFLAGS+=-I../molfile + * CPPFLAGS+=-I../molfile */ #include "molfile/libmolfile_plugin.h" #include "molfile/molfile_plugin.h" @@ -59,7 +59,7 @@ using namespace PLMD::molfile; using namespace std; namespace PLMD { -namespace cltools{ +namespace cltools { //+PLUMEDOC TOOLS driver-float /* @@ -89,7 +89,7 @@ The input to driver is specified using the command line arguments described belo In addition, you can use the special \subpage READ command inside your plumed input to read in colvar files that were generated during your MD simulation. The values -read in can then be treated like calculated colvars. +read in can then be treated like calculated colvars. \warning Notice that by default the driver has no knowledge about the masses and charges @@ -133,7 +133,7 @@ To have support of all of VMD's plugins you need to recompile PLUMED. You need to download the SOURCE of VMD, which contains a plugins directory. Adapt build.sh and compile it. At the end, you should get the molfile plugins compiled as a static -library libmolfile_plugin.a. Locate said file and libmolfile_plugin.h, +library libmolfile_plugin.a. Locate said file and libmolfile_plugin.h, and customize the configure command with something along the lines of: @@ -169,15 +169,15 @@ is more robust than the molfile one, since it provides support for generic cell #ifdef __PLUMED_HAS_MOLFILE_PLUGINS static vector<molfile_plugin_t *> plugins; static map <string, unsigned> pluginmap; -static int register_cb(void *v, vmdplugin_t *p){ +static int register_cb(void *v, vmdplugin_t *p) { //const char *key = p->name; const auto ret = pluginmap.insert ( std::pair<string,unsigned>(string(p->name),plugins.size()) ); - if (ret.second==false) { - //cerr<<"MOLFILE: found duplicate plugin for "<<key<<" : not inserted "<<endl; - }else{ - //cerr<<"MOLFILE: loading plugin "<<key<<" number "<<plugins.size()-1<<endl; - plugins.push_back(reinterpret_cast<molfile_plugin_t *>(p)); - } + if (ret.second==false) { + //cerr<<"MOLFILE: found duplicate plugin for "<<key<<" : not inserted "<<endl; + } else { + //cerr<<"MOLFILE: loading plugin "<<key<<" number "<<plugins.size()-1<<endl; + plugins.push_back(reinterpret_cast<molfile_plugin_t *>(p)); + } return VMDPLUGIN_SUCCESS; } #endif @@ -195,15 +195,15 @@ public: }; template<typename real> -void Driver<real>::registerKeywords( Keywords& keys ){ +void Driver<real>::registerKeywords( Keywords& keys ) { CLTool::registerKeywords( keys ); keys.isDriver(); keys.addFlag("--help-debug",false,"print special options that can be used to create regtests"); keys.add("compulsory","--plumed","plumed.dat","specify the name of the plumed input file"); keys.add("compulsory","--timestep","1.0","the timestep that was used in the calculation that produced this trajectory in picoseconds"); keys.add("compulsory","--trajectory-stride","1","the frequency with which frames were output to this trajectory during the simulation" #ifdef __PLUMED_HAS_XDRFILE - " (0 means that the number of the step is read from the trajectory file," - " currently working only for xtc/trr files read with --ixtc/--trr)" + " (0 means that the number of the step is read from the trajectory file," + " currently working only for xtc/trr files read with --ixtc/--trr)" #endif ); keys.add("compulsory","--multi","0","set number of replicas for multi environment (needs mpi)"); @@ -225,7 +225,7 @@ void Driver<real>::registerKeywords( Keywords& keys ){ keys.add("optional","--box","comma-separated box dimensions (3 for orthorombic, 9 for generic)"); keys.add("optional","--natoms","provides number of atoms - only used if file format does not contain number of atoms"); keys.add("optional","--debug-forces","output a file containing the forces due to the bias evaluated using numerical derivatives " - "and using the analytical derivatives implemented in plumed"); + "and using the analytical derivatives implemented in plumed"); keys.add("hidden","--debug-float","turns on the single precision version (to check float interface)"); keys.add("hidden","--debug-dd","use a fake domain decomposition"); keys.add("hidden","--debug-pd","use a fake particle decomposition"); @@ -234,56 +234,56 @@ void Driver<real>::registerKeywords( Keywords& keys ){ #ifdef __PLUMED_HAS_MOLFILE_PLUGINS MOLFILE_INIT_ALL MOLFILE_REGISTER_ALL(NULL, register_cb) - for(int i=0;i<plugins.size();i++){ - string kk="--mf_"+string(plugins[i]->name); - string mm=" molfile: the trajectory in "+string(plugins[i]->name)+" format " ; - //cerr<<"REGISTERING "<<kk<<mm<<endl; - keys.add("atoms",kk,mm); + for(int i=0; i<plugins.size(); i++) { + string kk="--mf_"+string(plugins[i]->name); + string mm=" molfile: the trajectory in "+string(plugins[i]->name)+" format " ; + //cerr<<"REGISTERING "<<kk<<mm<<endl; + keys.add("atoms",kk,mm); } #endif } template<typename real> Driver<real>::Driver(const CLToolOptions& co ): -CLTool(co) + CLTool(co) { - inputdata=commandline; + inputdata=commandline; } template<typename real> -string Driver<real>::description()const{ return "analyze trajectories with plumed"; } +string Driver<real>::description()const { return "analyze trajectories with plumed"; } template<typename real> -int Driver<real>::main(FILE* in,FILE*out,Communicator& pc){ +int Driver<real>::main(FILE* in,FILE*out,Communicator& pc) { Units units; PDB pdb; // Parse everything bool printhelpdebug; parseFlag("--help-debug",printhelpdebug); - if( printhelpdebug ){ - fprintf(out,"%s", - "Additional options for debug (only to be used in regtest):\n" - " [--debug-float] : turns on the single precision version (to check float interface)\n" - " [--debug-dd] : use a fake domain decomposition\n" - " [--debug-pd] : use a fake particle decomposition\n" - ); - return 0; + if( printhelpdebug ) { + fprintf(out,"%s", + "Additional options for debug (only to be used in regtest):\n" + " [--debug-float] : turns on the single precision version (to check float interface)\n" + " [--debug-dd] : use a fake domain decomposition\n" + " [--debug-pd] : use a fake particle decomposition\n" + ); + return 0; } // Are we reading trajectory data bool noatoms; parseFlag("--noatoms",noatoms); - std::string fakein; + std::string fakein; bool debugfloat=parse("--debug-float",fakein); - if(debugfloat && sizeof(real)!=sizeof(float)){ - CLTool* cl=cltoolRegister().create(CLToolOptions("driver-float")); //new Driver<float>(*this); - cl->setInputData(this->getInputData()); - int ret=cl->main(in,out,pc); - delete cl; - return ret; + if(debugfloat && sizeof(real)!=sizeof(float)) { + CLTool* cl=cltoolRegister().create(CLToolOptions("driver-float")); //new Driver<float>(*this); + cl->setInputData(this->getInputData()); + int ret=cl->main(in,out,pc); + delete cl; + return ret; } bool debug_pd=parse("--debug-pd",fakein); bool debug_dd=parse("--debug-dd",fakein); - if( debug_pd || debug_dd ){ + if( debug_pd || debug_dd ) { if(noatoms) error("cannot debug without atoms"); } @@ -292,7 +292,7 @@ int Driver<real>::main(FILE* in,FILE*out,Communicator& pc){ parse("--multi",multi); Communicator intracomm; Communicator intercomm; - if(multi){ + if(multi) { int ntot=pc.Get_size(); int nintra=ntot/multi; if(multi*nintra!=ntot) error("invalid number of processes for multi environment"); @@ -306,20 +306,20 @@ int Driver<real>::main(FILE* in,FILE*out,Communicator& pc){ bool debug_grex=parse("--debug-grex",fakein); int grex_stride=0; FILE*grex_log=NULL; - if(debug_grex){ + if(debug_grex) { if(noatoms) error("must have atoms to debug_grex"); if(multi<2) error("--debug_grex needs --multi with at least two replicas"); Tools::convert(fakein,grex_stride); string n; Tools::convert(intercomm.Get_rank(),n); string file; parse("--debug-grex-log",file); - if(file.length()>0){ + if(file.length()>0) { file+="."+n; grex_log=fopen(file.c_str(),"w"); } } -// Read the plumed input file name +// Read the plumed input file name string plumedFile; parse("--plumed",plumedFile); // the timestep double t; parse("--timestep",t); @@ -327,11 +327,11 @@ int Driver<real>::main(FILE* in,FILE*out,Communicator& pc){ // the stride unsigned stride; parse("--trajectory-stride",stride); // are we writing forces - string dumpforces(""), debugforces(""), dumpforcesFmt("%f");; + string dumpforces(""), debugforces(""), dumpforcesFmt("%f");; bool dumpfullvirial=false; - if(!noatoms){ - parse("--dump-forces",dumpforces); - parse("--debug-forces",debugforces); + if(!noatoms) { + parse("--dump-forces",dumpforces); + parse("--debug-forces",debugforces); } if(dumpforces!="" || debugforces!="" ) parse("--dump-forces-fmt",dumpforcesFmt); if(dumpforces!="") parseFlag("--dump-full-virial",dumpfullvirial); @@ -340,11 +340,11 @@ int Driver<real>::main(FILE* in,FILE*out,Communicator& pc){ string trajectory_fmt; - bool use_molfile=false; + bool use_molfile=false; #ifdef __PLUMED_HAS_MOLFILE_PLUGINS - molfile_plugin_t *api=NULL; + molfile_plugin_t *api=NULL; void *h_in=NULL; - molfile_timestep_t ts_in; // this is the structure that has the timestep + molfile_timestep_t ts_in; // this is the structure that has the timestep ts_in.coords=NULL; ts_in.A=-1; // we use this to check whether cell is provided or not #endif @@ -354,99 +354,99 @@ int Driver<real>::main(FILE* in,FILE*out,Communicator& pc){ bool pbc_cli_given=false; vector<double> pbc_cli_box(9,0.0); int command_line_natoms=-1; - if(!noatoms){ - std::string traj_xyz; parse("--ixyz",traj_xyz); - std::string traj_gro; parse("--igro",traj_gro); - std::string traj_xtc; - std::string traj_trr; + if(!noatoms) { + std::string traj_xyz; parse("--ixyz",traj_xyz); + std::string traj_gro; parse("--igro",traj_gro); + std::string traj_xtc; + std::string traj_trr; #ifdef __PLUMED_HAS_XDRFILE - parse("--ixtc",traj_xtc); - parse("--itrr",traj_trr); + parse("--ixtc",traj_xtc); + parse("--itrr",traj_trr); #endif #ifdef __PLUMED_HAS_MOLFILE_PLUGINS - for(int i=0;i<plugins.size();i++){ - string molfile_key="--mf_"+string(plugins[i]->name); - string traj_molfile; - parse(molfile_key,traj_molfile); - if(traj_molfile.length()>0){ - fprintf(out,"\nDRIVER: Found molfile format trajectory %s with name %s\n",plugins[i]->name,traj_molfile.c_str()); - trajectoryFile=traj_molfile; - trajectory_fmt=string(plugins[i]->name); - use_molfile=true; - api = plugins[i]; - } - } + for(int i=0; i<plugins.size(); i++) { + string molfile_key="--mf_"+string(plugins[i]->name); + string traj_molfile; + parse(molfile_key,traj_molfile); + if(traj_molfile.length()>0) { + fprintf(out,"\nDRIVER: Found molfile format trajectory %s with name %s\n",plugins[i]->name,traj_molfile.c_str()); + trajectoryFile=traj_molfile; + trajectory_fmt=string(plugins[i]->name); + use_molfile=true; + api = plugins[i]; + } + } #endif - { // check that only one fmt is specified - int nn=0; - if(traj_xyz.length()>0) nn++; - if(traj_gro.length()>0) nn++; - if(traj_xtc.length()>0) nn++; - if(traj_trr.length()>0) nn++; - if(nn>1){ - fprintf(stderr,"ERROR: cannot provide more than one trajectory file\n"); - if(grex_log)fclose(grex_log); - return 1; - } - } - if(traj_xyz.length()>0 && trajectoryFile.length()==0){ - trajectoryFile=traj_xyz; - trajectory_fmt="xyz"; - } - if(traj_gro.length()>0 && trajectoryFile.length()==0){ - trajectoryFile=traj_gro; - trajectory_fmt="gro"; - } - if(traj_xtc.length()>0 && trajectoryFile.length()==0){ - trajectoryFile=traj_xtc; - trajectory_fmt="xdr-xtc"; - } - if(traj_trr.length()>0 && trajectoryFile.length()==0){ - trajectoryFile=traj_trr; - trajectory_fmt="xdr-trr"; - } - if(trajectoryFile.length()==0){ - fprintf(stderr,"ERROR: missing trajectory data\n"); - if(grex_log)fclose(grex_log); - return 1; - } - string lengthUnits(""); parse("--length-units",lengthUnits); - if(lengthUnits.length()>0) units.setLength(lengthUnits); - string chargeUnits(""); parse("--charge-units",chargeUnits); - if(chargeUnits.length()>0) units.setCharge(chargeUnits); - string massUnits(""); parse("--mass-units",massUnits); - if(massUnits.length()>0) units.setMass(massUnits); - - parse("--pdb",pdbfile); - if(pdbfile.length()>0){ - bool check=pdb.read(pdbfile,false,1.0); - if(!check) error("error reading pdb file"); - } - - parse("--mc",mcfile); - - string pbc_cli_list; parse("--box",pbc_cli_list); - if(pbc_cli_list.length()>0) { - pbc_cli_given=true; - vector<string> words=Tools::getWords(pbc_cli_list,","); - if(words.size()==3){ - for(int i=0;i<3;i++) sscanf(words[i].c_str(),"%100lf",&(pbc_cli_box[4*i])); - } else if(words.size()==9) { - for(int i=0;i<9;i++) sscanf(words[i].c_str(),"%100lf",&(pbc_cli_box[i])); - } else { - string msg="ERROR: cannot parse command-line box "+pbc_cli_list; - fprintf(stderr,"%s\n",msg.c_str()); - return 1; - } - - } - - parse("--natoms",command_line_natoms); - + { // check that only one fmt is specified + int nn=0; + if(traj_xyz.length()>0) nn++; + if(traj_gro.length()>0) nn++; + if(traj_xtc.length()>0) nn++; + if(traj_trr.length()>0) nn++; + if(nn>1) { + fprintf(stderr,"ERROR: cannot provide more than one trajectory file\n"); + if(grex_log)fclose(grex_log); + return 1; + } + } + if(traj_xyz.length()>0 && trajectoryFile.length()==0) { + trajectoryFile=traj_xyz; + trajectory_fmt="xyz"; + } + if(traj_gro.length()>0 && trajectoryFile.length()==0) { + trajectoryFile=traj_gro; + trajectory_fmt="gro"; + } + if(traj_xtc.length()>0 && trajectoryFile.length()==0) { + trajectoryFile=traj_xtc; + trajectory_fmt="xdr-xtc"; + } + if(traj_trr.length()>0 && trajectoryFile.length()==0) { + trajectoryFile=traj_trr; + trajectory_fmt="xdr-trr"; + } + if(trajectoryFile.length()==0) { + fprintf(stderr,"ERROR: missing trajectory data\n"); + if(grex_log)fclose(grex_log); + return 1; + } + string lengthUnits(""); parse("--length-units",lengthUnits); + if(lengthUnits.length()>0) units.setLength(lengthUnits); + string chargeUnits(""); parse("--charge-units",chargeUnits); + if(chargeUnits.length()>0) units.setCharge(chargeUnits); + string massUnits(""); parse("--mass-units",massUnits); + if(massUnits.length()>0) units.setMass(massUnits); + + parse("--pdb",pdbfile); + if(pdbfile.length()>0) { + bool check=pdb.read(pdbfile,false,1.0); + if(!check) error("error reading pdb file"); + } + + parse("--mc",mcfile); + + string pbc_cli_list; parse("--box",pbc_cli_list); + if(pbc_cli_list.length()>0) { + pbc_cli_given=true; + vector<string> words=Tools::getWords(pbc_cli_list,","); + if(words.size()==3) { + for(int i=0; i<3; i++) sscanf(words[i].c_str(),"%100lf",&(pbc_cli_box[4*i])); + } else if(words.size()==9) { + for(int i=0; i<9; i++) sscanf(words[i].c_str(),"%100lf",&(pbc_cli_box[i])); + } else { + string msg="ERROR: cannot parse command-line box "+pbc_cli_list; + fprintf(stderr,"%s\n",msg.c_str()); + return 1; + } + + } + + parse("--natoms",command_line_natoms); + } if( debug_dd && debug_pd ) error("cannot use debug-dd and debug-pd at the same time"); - if(debug_pd || debug_dd){ + if(debug_pd || debug_dd) { if( !Communicator::initialized() ) error("needs mpi for debug-pd"); } @@ -455,14 +455,14 @@ int Driver<real>::main(FILE* in,FILE*out,Communicator& pc){ p.cmd("setRealPrecision",&rr); int checknatoms=-1; long int step=0; - if(Communicator::initialized()){ - if(multi){ + if(Communicator::initialized()) { + if(multi) { if(intracomm.Get_rank()==0) p.cmd("GREX setMPIIntercomm",&intercomm.Get_comm()); p.cmd("GREX setMPIIntracomm",&intracomm.Get_comm()); p.cmd("GREX init"); - } + } p.cmd("setMPIComm",&intracomm.Get_comm()); - } + } p.cmd("setMDLengthUnits",&units.getLength()); p.cmd("setMDChargeUnits",&units.getCharge()); p.cmd("setMDMassUnits",&units.getMass()); @@ -471,7 +471,7 @@ int Driver<real>::main(FILE* in,FILE*out,Communicator& pc){ p.cmd("setPlumedDat",plumedFile.c_str()); p.cmd("setLog",out); - if(multi){ + if(multi) { string n; Tools::convert(intercomm.Get_rank(),n); trajectoryFile=FileBase::appendSuffix(trajectoryFile,"."+n); @@ -484,57 +484,57 @@ int Driver<real>::main(FILE* in,FILE*out,Communicator& pc){ #ifdef __PLUMED_HAS_XDRFILE XDRFILE* xd=NULL; #endif - if(!noatoms){ - if (trajectoryFile=="-") - fp=in; - else { - if(use_molfile==true){ + if(!noatoms) { + if (trajectoryFile=="-") + fp=in; + else { + if(use_molfile==true) { #ifdef __PLUMED_HAS_MOLFILE_PLUGINS h_in = api->open_file_read(trajectoryFile.c_str(), trajectory_fmt.c_str(), &natoms); - if(natoms==MOLFILE_NUMATOMS_UNKNOWN){ + if(natoms==MOLFILE_NUMATOMS_UNKNOWN) { if(command_line_natoms>=0) natoms=command_line_natoms; else error("this file format does not provide number of atoms; use --natoms on the command line"); } ts_in.coords = new float [3*natoms]; #endif - }else if(trajectory_fmt=="xdr-xtc" || trajectory_fmt=="xdr-trr"){ + } else if(trajectory_fmt=="xdr-xtc" || trajectory_fmt=="xdr-trr") { #ifdef __PLUMED_HAS_XDRFILE - xd=xdrfile_open(trajectoryFile.c_str(),"r"); - if(!xd){ - string msg="ERROR: Error opening trajectory file "+trajectoryFile; - fprintf(stderr,"%s\n",msg.c_str()); - return 1; - } - if(trajectory_fmt=="xdr-xtc") read_xtc_natoms(&trajectoryFile[0],&natoms); - if(trajectory_fmt=="xdr-trr") read_trr_natoms(&trajectoryFile[0],&natoms); + xd=xdrfile_open(trajectoryFile.c_str(),"r"); + if(!xd) { + string msg="ERROR: Error opening trajectory file "+trajectoryFile; + fprintf(stderr,"%s\n",msg.c_str()); + return 1; + } + if(trajectory_fmt=="xdr-xtc") read_xtc_natoms(&trajectoryFile[0],&natoms); + if(trajectory_fmt=="xdr-trr") read_trr_natoms(&trajectoryFile[0],&natoms); #endif - }else{ - fp=fopen(trajectoryFile.c_str(),"r"); - if(!fp){ - string msg="ERROR: Error opening trajectory file "+trajectoryFile; - fprintf(stderr,"%s\n",msg.c_str()); + } else { + fp=fopen(trajectoryFile.c_str(),"r"); + if(!fp) { + string msg="ERROR: Error opening trajectory file "+trajectoryFile; + fprintf(stderr,"%s\n",msg.c_str()); // cppcheck detects a false positive here. I suppress it: // cppcheck-suppress memleak - return 1; - } - } - } - if(dumpforces.length()>0){ - if(Communicator::initialized() && pc.Get_size()>1){ - string n; - Tools::convert(pc.Get_rank(),n); - dumpforces+="."+n; - } - fp_forces=fopen(dumpforces.c_str(),"w"); - } - if(debugforces.length()>0){ - if(Communicator::initialized() && pc.Get_size()>1){ - string n; - Tools::convert(pc.Get_rank(),n); - debugforces+="."+n; - } - fp_dforces.open(debugforces); - } + return 1; + } + } + } + if(dumpforces.length()>0) { + if(Communicator::initialized() && pc.Get_size()>1) { + string n; + Tools::convert(pc.Get_rank(),n); + dumpforces+="."+n; + } + fp_forces=fopen(dumpforces.c_str(),"w"); + } + if(debugforces.length()>0) { + if(Communicator::initialized() && pc.Get_size()>1) { + string n; + Tools::convert(pc.Get_rank(),n); + debugforces+="."+n; + } + fp_dforces.open(debugforces); + } } std::string line; @@ -560,41 +560,41 @@ int Driver<real>::main(FILE* in,FILE*out,Communicator& pc){ // random stream to choose decompositions Random rnd; - while(true){ - if(!noatoms){ - if(use_molfile==true){ + while(true) { + if(!noatoms) { + if(use_molfile==true) { #ifdef __PLUMED_HAS_MOLFILE_PLUGINS - int rc; - rc = api->read_next_timestep(h_in, natoms, &ts_in); - //if(rc==MOLFILE_SUCCESS){ - // printf(" read this one :success \n"); - //} - if(rc==MOLFILE_EOF){ - //printf(" read this one :eof or error \n"); - break; - } + int rc; + rc = api->read_next_timestep(h_in, natoms, &ts_in); + //if(rc==MOLFILE_SUCCESS){ + // printf(" read this one :success \n"); + //} + if(rc==MOLFILE_EOF) { + //printf(" read this one :eof or error \n"); + break; + } #endif - }else if(trajectory_fmt=="xyz" || trajectory_fmt=="gro"){ - if(!Tools::getline(fp,line)) break; - } + } else if(trajectory_fmt=="xyz" || trajectory_fmt=="gro") { + if(!Tools::getline(fp,line)) break; + } } bool first_step=false; - if(!noatoms){ - if(use_molfile==false && (trajectory_fmt=="xyz" || trajectory_fmt=="gro")){ + if(!noatoms) { + if(use_molfile==false && (trajectory_fmt=="xyz" || trajectory_fmt=="gro")) { if(trajectory_fmt=="gro") if(!Tools::getline(fp,line)) error("premature end of trajectory file"); sscanf(line.c_str(),"%100d",&natoms); } } - if(checknatoms<0 && !noatoms){ + if(checknatoms<0 && !noatoms) { pd_nlocal=natoms; pd_start=0; first_step=true; masses.assign(natoms,NAN); charges.assign(natoms,NAN); //case pdb: structure - if(pdbfile.length()>0){ - for(unsigned i=0;i<pdb.size();++i){ + if(pdbfile.length()>0) { + for(unsigned i=0; i<pdb.size(); ++i) { AtomNumber an=pdb.getAtomNumbers()[i]; unsigned index=an.index(); if( index>=unsigned(natoms) ) error("atom index in pdb exceeds the number of atoms in trajectory"); @@ -602,26 +602,26 @@ int Driver<real>::main(FILE* in,FILE*out,Communicator& pc){ charges[index]=pdb.getBeta()[i]; } } - if(mcfile.length()>0){ + if(mcfile.length()>0) { IFile ifile; ifile.open(mcfile); int index; double mass; double charge; - while(ifile.scanField("index",index).scanField("mass",mass).scanField("charge",charge).scanField()){ + while(ifile.scanField("index",index).scanField("mass",mass).scanField("charge",charge).scanField()) { masses[index]=mass; charges[index]=charge; } } - } else if( checknatoms<0 && noatoms ){ - natoms=0; + } else if( checknatoms<0 && noatoms ) { + natoms=0; } - if( checknatoms<0 ){ + if( checknatoms<0 ) { checknatoms=natoms; p.cmd("setNatoms",&natoms); p.cmd("init"); } - if(checknatoms!=natoms){ - std::string stepstr; Tools::convert(step,stepstr); - error("number of atoms in frame " + stepstr + " does not match number of atoms in first frame"); + if(checknatoms!=natoms) { + std::string stepstr; Tools::convert(step,stepstr); + error("number of atoms in frame " + stepstr + " does not match number of atoms in first frame"); } coordinates.assign(3*natoms,real(0.0)); @@ -629,12 +629,12 @@ int Driver<real>::main(FILE* in,FILE*out,Communicator& pc){ cell.assign(9,real(0.0)); virial.assign(9,real(0.0)); - if( first_step || rnd.U01()>0.5){ - if(debug_pd){ + if( first_step || rnd.U01()>0.5) { + if(debug_pd) { int npe=intracomm.Get_size(); vector<int> loc(npe,0); vector<int> start(npe,0); - for(int i=0;i<npe-1;i++){ + for(int i=0; i<npe-1; i++) { int cc=(natoms*2*rnd.U01())/npe; if(start[i]+cc>natoms) cc=natoms-start[i]; loc[i]=cc; @@ -645,14 +645,14 @@ int Driver<real>::main(FILE* in,FILE*out,Communicator& pc){ intracomm.Bcast(start,0); pd_nlocal=loc[intracomm.Get_rank()]; pd_start=start[intracomm.Get_rank()]; - if(intracomm.Get_rank()==0){ + if(intracomm.Get_rank()==0) { fprintf(out,"\nDRIVER: Reassigning particle decomposition\n"); - fprintf(out,"DRIVER: "); for(int i=0;i<npe;i++) fprintf(out,"%d ",loc[i]); printf("\n"); - fprintf(out,"DRIVER: "); for(int i=0;i<npe;i++) fprintf(out,"%d ",start[i]); printf("\n"); + fprintf(out,"DRIVER: "); for(int i=0; i<npe; i++) fprintf(out,"%d ",loc[i]); printf("\n"); + fprintf(out,"DRIVER: "); for(int i=0; i<npe; i++) fprintf(out,"%d ",start[i]); printf("\n"); } p.cmd("setAtomsNlocal",&pd_nlocal); p.cmd("setAtomsContiguous",&pd_start); - } else if(debug_dd){ + } else if(debug_dd) { int npe=intracomm.Get_size(); int rank=intracomm.Get_rank(); dd_charges.assign(natoms,0.0); @@ -662,11 +662,11 @@ int Driver<real>::main(FILE* in,FILE*out,Communicator& pc){ dd_coordinates.assign(3*natoms,0.0); dd_forces.assign(3*natoms,0.0); dd_nlocal=0; - for(int i=0;i<natoms;++i){ + for(int i=0; i<natoms; ++i) { double r=rnd.U01()*npe; - int n; for(n=0;n<npe;n++) if(n+1>r)break; + int n; for(n=0; n<npe; n++) if(n+1>r)break; plumed_assert(n<npe); - if(n==rank){ + if(n==rank) { dd_gatindex[dd_nlocal]=i; dd_g2l[i]=dd_nlocal; dd_charges[dd_nlocal]=charges[i]; @@ -674,7 +674,7 @@ int Driver<real>::main(FILE* in,FILE*out,Communicator& pc){ dd_nlocal++; } } - if(intracomm.Get_rank()==0){ + if(intracomm.Get_rank()==0) { fprintf(out,"\nDRIVER: Reassigning particle decomposition\n"); } p.cmd("setAtomsNlocal",&dd_nlocal); @@ -683,232 +683,232 @@ int Driver<real>::main(FILE* in,FILE*out,Communicator& pc){ } int plumedStopCondition=0; - if(!noatoms){ - if(use_molfile){ + if(!noatoms) { + if(use_molfile) { #ifdef __PLUMED_HAS_MOLFILE_PLUGINS - if(pbc_cli_given==false) { - if(ts_in.A>0.0){ // this is negative if molfile does not provide box - // info on the cell: convert using pbcset.tcl from pbctools in vmd distribution - real cosBC=cos(ts_in.alpha*pi/180.); - //double sinBC=sin(ts_in.alpha*pi/180.); - real cosAC=cos(ts_in.beta*pi/180.); - real cosAB=cos(ts_in.gamma*pi/180.); - real sinAB=sin(ts_in.gamma*pi/180.); - real Ax=ts_in.A; - real Bx=ts_in.B*cosAB; - real By=ts_in.B*sinAB; - real Cx=ts_in.C*cosAC; - real Cy=(ts_in.C*ts_in.B*cosBC-Cx*Bx)/By; - real Cz=sqrt(ts_in.C*ts_in.C-Cx*Cx-Cy*Cy); - cell[0]=Ax/10.;cell[1]=0.;cell[2]=0.; - cell[3]=Bx/10.;cell[4]=By/10.;cell[5]=0.; - cell[6]=Cx/10.;cell[7]=Cy/10.;cell[8]=Cz/10.; - } else { - cell[0]=0.0; cell[1]=0.0; cell[2]=0.0; - cell[3]=0.0; cell[4]=0.0; cell[5]=0.0; - cell[6]=0.0; cell[7]=0.0; cell[8]=0.0; - } - }else{ - for(unsigned i=0;i<9;i++)cell[i]=pbc_cli_box[i]; - } - // info on coords - // the order is xyzxyz... - for(unsigned i=0;i<3*natoms;i++){ - coordinates[i]=real(ts_in.coords[i]/10.); //convert to nm - //cerr<<"COOR "<<coordinates[i]<<endl; - } + if(pbc_cli_given==false) { + if(ts_in.A>0.0) { // this is negative if molfile does not provide box + // info on the cell: convert using pbcset.tcl from pbctools in vmd distribution + real cosBC=cos(ts_in.alpha*pi/180.); + //double sinBC=sin(ts_in.alpha*pi/180.); + real cosAC=cos(ts_in.beta*pi/180.); + real cosAB=cos(ts_in.gamma*pi/180.); + real sinAB=sin(ts_in.gamma*pi/180.); + real Ax=ts_in.A; + real Bx=ts_in.B*cosAB; + real By=ts_in.B*sinAB; + real Cx=ts_in.C*cosAC; + real Cy=(ts_in.C*ts_in.B*cosBC-Cx*Bx)/By; + real Cz=sqrt(ts_in.C*ts_in.C-Cx*Cx-Cy*Cy); + cell[0]=Ax/10.; cell[1]=0.; cell[2]=0.; + cell[3]=Bx/10.; cell[4]=By/10.; cell[5]=0.; + cell[6]=Cx/10.; cell[7]=Cy/10.; cell[8]=Cz/10.; + } else { + cell[0]=0.0; cell[1]=0.0; cell[2]=0.0; + cell[3]=0.0; cell[4]=0.0; cell[5]=0.0; + cell[6]=0.0; cell[7]=0.0; cell[8]=0.0; + } + } else { + for(unsigned i=0; i<9; i++)cell[i]=pbc_cli_box[i]; + } + // info on coords + // the order is xyzxyz... + for(unsigned i=0; i<3*natoms; i++) { + coordinates[i]=real(ts_in.coords[i]/10.); //convert to nm + //cerr<<"COOR "<<coordinates[i]<<endl; + } #endif - }else if(trajectory_fmt=="xdr-xtc" || trajectory_fmt=="xdr-trr"){ + } else if(trajectory_fmt=="xdr-xtc" || trajectory_fmt=="xdr-trr") { #ifdef __PLUMED_HAS_XDRFILE - int localstep; - float time; - matrix box; - rvec* pos=new rvec[natoms]; - float prec,lambda; - int ret; - if(trajectory_fmt=="xdr-xtc") ret=read_xtc(xd,natoms,&localstep,&time,box,pos,&prec); - if(trajectory_fmt=="xdr-trr") ret=read_trr(xd,natoms,&localstep,&time,&lambda,box,pos,NULL,NULL); - if(stride==0) step=localstep; - if(ret==exdrENDOFFILE) break; - if(ret!=exdrOK) break; - for(unsigned i=0;i<3;i++) for(unsigned j=0;j<3;j++) cell[3*i+j]=box[i][j]; - for(unsigned i=0;i<natoms;i++) for(unsigned j=0;j<3;j++) - coordinates[3*i+j]=real(pos[i][j]); - delete [] pos; + int localstep; + float time; + matrix box; + rvec* pos=new rvec[natoms]; + float prec,lambda; + int ret; + if(trajectory_fmt=="xdr-xtc") ret=read_xtc(xd,natoms,&localstep,&time,box,pos,&prec); + if(trajectory_fmt=="xdr-trr") ret=read_trr(xd,natoms,&localstep,&time,&lambda,box,pos,NULL,NULL); + if(stride==0) step=localstep; + if(ret==exdrENDOFFILE) break; + if(ret!=exdrOK) break; + for(unsigned i=0; i<3; i++) for(unsigned j=0; j<3; j++) cell[3*i+j]=box[i][j]; + for(unsigned i=0; i<natoms; i++) for(unsigned j=0; j<3; j++) + coordinates[3*i+j]=real(pos[i][j]); + delete [] pos; #endif - }else{ - if(trajectory_fmt=="xyz"){ - if(!Tools::getline(fp,line)) error("premature end of trajectory file"); - - std::vector<double> celld(9,0.0); - if(pbc_cli_given==false) { - std::vector<std::string> words; - words=Tools::getWords(line); - if(words.size()==3){ - sscanf(line.c_str(),"%100lf %100lf %100lf",&celld[0],&celld[4],&celld[8]); - } else if(words.size()==9){ - sscanf(line.c_str(),"%100lf %100lf %100lf %100lf %100lf %100lf %100lf %100lf %100lf", - &celld[0], &celld[1], &celld[2], - &celld[3], &celld[4], &celld[5], - &celld[6], &celld[7], &celld[8]); - } else error("needed box in second line of xyz file"); - } else { // from command line - celld=pbc_cli_box; - } - for(unsigned i=0;i<9;i++)cell[i]=real(celld[i]); - } - int ddist=0; - // Read coordinates - for(int i=0;i<natoms;i++){ - bool ok=Tools::getline(fp,line); - if(!ok) error("premature end of trajectory file"); - double cc[3]; - if(trajectory_fmt=="xyz"){ - char dummy[1000]; - int ret=std::sscanf(line.c_str(),"%999s %100lf %100lf %100lf",dummy,&cc[0],&cc[1],&cc[2]); - if(ret!=4) error("cannot read line"+line); - } else if(trajectory_fmt=="gro"){ - // do the gromacs way - if(!i){ - // - // calculate the distance between dots (as in gromacs gmxlib/confio.c, routine get_w_conf ) - // - const char *p1, *p2, *p3; - p1 = strchr(line.c_str(), '.'); - if (p1 == NULL) error("seems there are no coordinates in the gro file"); - p2 = strchr(&p1[1], '.'); - if (p2 == NULL) error("seems there is only one coordinates in the gro file"); - ddist = p2 - p1; - p3 = strchr(&p2[1], '.'); - if (p3 == NULL)error("seems there are only two coordinates in the gro file"); - if (p3 - p2 != ddist)error("not uniform spacing in fields in the gro file"); - } - Tools::convert(line.substr(20,ddist),cc[0]); - Tools::convert(line.substr(20+ddist,ddist),cc[1]); - Tools::convert(line.substr(20+ddist+ddist,ddist),cc[2]); - } else plumed_error(); - if(!debug_pd || ( i>=pd_start && i<pd_start+pd_nlocal) ){ - coordinates[3*i]=real(cc[0]); - coordinates[3*i+1]=real(cc[1]); - coordinates[3*i+2]=real(cc[2]); - } - } - if(trajectory_fmt=="gro"){ - if(!Tools::getline(fp,line)) error("premature end of trajectory file"); - std::vector<string> words=Tools::getWords(line); - if(words.size()<3) error("cannot understand box format"); - Tools::convert(words[0],cell[0]); - Tools::convert(words[1],cell[4]); - Tools::convert(words[2],cell[8]); - if(words.size()>3) Tools::convert(words[3],cell[1]); - if(words.size()>4) Tools::convert(words[4],cell[2]); - if(words.size()>5) Tools::convert(words[5],cell[3]); - if(words.size()>6) Tools::convert(words[6],cell[5]); - if(words.size()>7) Tools::convert(words[7],cell[6]); - if(words.size()>8) Tools::convert(words[8],cell[7]); - } - - } - - p.cmd("setStepLong",&step); - p.cmd("setStopFlag",&plumedStopCondition); - - if(debug_dd){ - for(int i=0;i<dd_nlocal;++i){ - int kk=dd_gatindex[i]; - dd_coordinates[3*i+0]=coordinates[3*kk+0]; - dd_coordinates[3*i+1]=coordinates[3*kk+1]; - dd_coordinates[3*i+2]=coordinates[3*kk+2]; - } - p.cmd("setForces",&dd_forces[0]); - p.cmd("setPositions",&dd_coordinates[0]); - p.cmd("setMasses",&dd_masses[0]); - p.cmd("setCharges",&dd_charges[0]); - } else { - p.cmd("setForces",&forces[3*pd_start]); - p.cmd("setPositions",&coordinates[3*pd_start]); - p.cmd("setMasses",&masses[pd_start]); - p.cmd("setCharges",&charges[pd_start]); - } - p.cmd("setBox",&cell[0]); - p.cmd("setVirial",&virial[0]); - }else{ - p.cmd("setStepLong",&step); - p.cmd("setStopFlag",&plumedStopCondition); - } - p.cmd("calc"); + } else { + if(trajectory_fmt=="xyz") { + if(!Tools::getline(fp,line)) error("premature end of trajectory file"); + + std::vector<double> celld(9,0.0); + if(pbc_cli_given==false) { + std::vector<std::string> words; + words=Tools::getWords(line); + if(words.size()==3) { + sscanf(line.c_str(),"%100lf %100lf %100lf",&celld[0],&celld[4],&celld[8]); + } else if(words.size()==9) { + sscanf(line.c_str(),"%100lf %100lf %100lf %100lf %100lf %100lf %100lf %100lf %100lf", + &celld[0], &celld[1], &celld[2], + &celld[3], &celld[4], &celld[5], + &celld[6], &celld[7], &celld[8]); + } else error("needed box in second line of xyz file"); + } else { // from command line + celld=pbc_cli_box; + } + for(unsigned i=0; i<9; i++)cell[i]=real(celld[i]); + } + int ddist=0; + // Read coordinates + for(int i=0; i<natoms; i++) { + bool ok=Tools::getline(fp,line); + if(!ok) error("premature end of trajectory file"); + double cc[3]; + if(trajectory_fmt=="xyz") { + char dummy[1000]; + int ret=std::sscanf(line.c_str(),"%999s %100lf %100lf %100lf",dummy,&cc[0],&cc[1],&cc[2]); + if(ret!=4) error("cannot read line"+line); + } else if(trajectory_fmt=="gro") { + // do the gromacs way + if(!i) { + // + // calculate the distance between dots (as in gromacs gmxlib/confio.c, routine get_w_conf ) + // + const char *p1, *p2, *p3; + p1 = strchr(line.c_str(), '.'); + if (p1 == NULL) error("seems there are no coordinates in the gro file"); + p2 = strchr(&p1[1], '.'); + if (p2 == NULL) error("seems there is only one coordinates in the gro file"); + ddist = p2 - p1; + p3 = strchr(&p2[1], '.'); + if (p3 == NULL)error("seems there are only two coordinates in the gro file"); + if (p3 - p2 != ddist)error("not uniform spacing in fields in the gro file"); + } + Tools::convert(line.substr(20,ddist),cc[0]); + Tools::convert(line.substr(20+ddist,ddist),cc[1]); + Tools::convert(line.substr(20+ddist+ddist,ddist),cc[2]); + } else plumed_error(); + if(!debug_pd || ( i>=pd_start && i<pd_start+pd_nlocal) ) { + coordinates[3*i]=real(cc[0]); + coordinates[3*i+1]=real(cc[1]); + coordinates[3*i+2]=real(cc[2]); + } + } + if(trajectory_fmt=="gro") { + if(!Tools::getline(fp,line)) error("premature end of trajectory file"); + std::vector<string> words=Tools::getWords(line); + if(words.size()<3) error("cannot understand box format"); + Tools::convert(words[0],cell[0]); + Tools::convert(words[1],cell[4]); + Tools::convert(words[2],cell[8]); + if(words.size()>3) Tools::convert(words[3],cell[1]); + if(words.size()>4) Tools::convert(words[4],cell[2]); + if(words.size()>5) Tools::convert(words[5],cell[3]); + if(words.size()>6) Tools::convert(words[6],cell[5]); + if(words.size()>7) Tools::convert(words[7],cell[6]); + if(words.size()>8) Tools::convert(words[8],cell[7]); + } + + } + + p.cmd("setStepLong",&step); + p.cmd("setStopFlag",&plumedStopCondition); + + if(debug_dd) { + for(int i=0; i<dd_nlocal; ++i) { + int kk=dd_gatindex[i]; + dd_coordinates[3*i+0]=coordinates[3*kk+0]; + dd_coordinates[3*i+1]=coordinates[3*kk+1]; + dd_coordinates[3*i+2]=coordinates[3*kk+2]; + } + p.cmd("setForces",&dd_forces[0]); + p.cmd("setPositions",&dd_coordinates[0]); + p.cmd("setMasses",&dd_masses[0]); + p.cmd("setCharges",&dd_charges[0]); + } else { + p.cmd("setForces",&forces[3*pd_start]); + p.cmd("setPositions",&coordinates[3*pd_start]); + p.cmd("setMasses",&masses[pd_start]); + p.cmd("setCharges",&charges[pd_start]); + } + p.cmd("setBox",&cell[0]); + p.cmd("setVirial",&virial[0]); + } else { + p.cmd("setStepLong",&step); + p.cmd("setStopFlag",&plumedStopCondition); + } + p.cmd("calc"); // this is necessary as only processor zero is adding to the virial: - intracomm.Bcast(virial,0); - if(debug_pd) intracomm.Sum(forces); - if(debug_dd){ - for(int i=0;i<dd_nlocal;i++){ - forces[3*dd_gatindex[i]+0]=dd_forces[3*i+0]; - forces[3*dd_gatindex[i]+1]=dd_forces[3*i+1]; - forces[3*dd_gatindex[i]+2]=dd_forces[3*i+2]; - } - dd_forces.assign(3*natoms,0.0); - intracomm.Sum(forces); - } - if(debug_grex &&step%grex_stride==0){ - p.cmd("GREX savePositions"); - if(intracomm.Get_rank()>0){ - p.cmd("GREX prepare"); - } else { - int r=intercomm.Get_rank(); - int n=intercomm.Get_size(); - int partner=r+(2*((r+step/grex_stride)%2))-1; - if(partner<0)partner=0; - if(partner>=n) partner=n-1; - p.cmd("GREX setPartner",&partner); - p.cmd("GREX calculate"); - p.cmd("GREX shareAllDeltaBias"); - for(int i=0;i<n;i++){ - string s; Tools::convert(i,s); - real a; s="GREX getDeltaBias "+s; p.cmd(s.c_str(),&a); - if(grex_log) fprintf(grex_log," %f",a); - } - if(grex_log) fprintf(grex_log,"\n"); - } - } - - - if(fp_forces){ - fprintf(fp_forces,"%d\n",natoms); - string fmtv=dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+"\n"; - string fmt=dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+"\n"; - if(dumpfullvirial){ - fprintf(fp_forces,fmtv.c_str(),virial[0],virial[1],virial[2],virial[3],virial[4],virial[5],virial[6],virial[7],virial[8]); - } else { - fprintf(fp_forces,fmt.c_str(),virial[0],virial[4],virial[8]); - } - fmt="X "+fmt; - for(int i=0;i<natoms;i++) - fprintf(fp_forces,fmt.c_str(),forces[3*i],forces[3*i+1],forces[3*i+2]); - } - if(debugforces.length()>0){ + intracomm.Bcast(virial,0); + if(debug_pd) intracomm.Sum(forces); + if(debug_dd) { + for(int i=0; i<dd_nlocal; i++) { + forces[3*dd_gatindex[i]+0]=dd_forces[3*i+0]; + forces[3*dd_gatindex[i]+1]=dd_forces[3*i+1]; + forces[3*dd_gatindex[i]+2]=dd_forces[3*i+2]; + } + dd_forces.assign(3*natoms,0.0); + intracomm.Sum(forces); + } + if(debug_grex &&step%grex_stride==0) { + p.cmd("GREX savePositions"); + if(intracomm.Get_rank()>0) { + p.cmd("GREX prepare"); + } else { + int r=intercomm.Get_rank(); + int n=intercomm.Get_size(); + int partner=r+(2*((r+step/grex_stride)%2))-1; + if(partner<0)partner=0; + if(partner>=n) partner=n-1; + p.cmd("GREX setPartner",&partner); + p.cmd("GREX calculate"); + p.cmd("GREX shareAllDeltaBias"); + for(int i=0; i<n; i++) { + string s; Tools::convert(i,s); + real a; s="GREX getDeltaBias "+s; p.cmd(s.c_str(),&a); + if(grex_log) fprintf(grex_log," %f",a); + } + if(grex_log) fprintf(grex_log,"\n"); + } + } + + + if(fp_forces) { + fprintf(fp_forces,"%d\n",natoms); + string fmtv=dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+"\n"; + string fmt=dumpforcesFmt+" "+dumpforcesFmt+" "+dumpforcesFmt+"\n"; + if(dumpfullvirial) { + fprintf(fp_forces,fmtv.c_str(),virial[0],virial[1],virial[2],virial[3],virial[4],virial[5],virial[6],virial[7],virial[8]); + } else { + fprintf(fp_forces,fmt.c_str(),virial[0],virial[4],virial[8]); + } + fmt="X "+fmt; + for(int i=0; i<natoms; i++) + fprintf(fp_forces,fmt.c_str(),forces[3*i],forces[3*i+1],forces[3*i+2]); + } + if(debugforces.length()>0) { // Now call the routine to work out the derivatives numerically numder.assign(3*natoms+9,real(0.0)); real base=0; p.cmd("getBias",&base); if( fabs(base)<epsilon ) printf("WARNING: bias for configuration appears to be zero so debugging forces is trivial"); - evaluateNumericalDerivatives( step, p, coordinates, masses, charges, cell, base, numder ); + evaluateNumericalDerivatives( step, p, coordinates, masses, charges, cell, base, numder ); // And output everything to a file fp_dforces.fmtField(" " + dumpforcesFmt); - for(int i=0;i<3*natoms;++i){ - fp_dforces.printField("parameter",(int)i); - fp_dforces.printField("analytical",forces[i]); - fp_dforces.printField("numerical",-numder[i]); - fp_dforces.printField(); + for(int i=0; i<3*natoms; ++i) { + fp_dforces.printField("parameter",(int)i); + fp_dforces.printField("analytical",forces[i]); + fp_dforces.printField("numerical",-numder[i]); + fp_dforces.printField(); } // And print the virial - for(int i=0;i<9;++i){ - fp_dforces.printField("parameter",3*natoms+i ); - fp_dforces.printField("analytical",virial[i] ); - fp_dforces.printField("numerical",-numder[3*natoms+i]); - fp_dforces.printField(); + for(int i=0; i<9; ++i) { + fp_dforces.printField("parameter",3*natoms+i ); + fp_dforces.printField("analytical",virial[i] ); + fp_dforces.printField("numerical",-numder[3*natoms+i]); + fp_dforces.printField(); } - } + } if(noatoms && plumedStopCondition) break; @@ -933,61 +933,61 @@ int Driver<real>::main(FILE* in,FILE*out,Communicator& pc){ template<typename real> void Driver<real>::evaluateNumericalDerivatives( const long int& step, Plumed& p, const std::vector<real>& coordinates, - const std::vector<real>& masses, const std::vector<real>& charges, - std::vector<real>& cell, const double& base, std::vector<real>& numder ){ + const std::vector<real>& masses, const std::vector<real>& charges, + std::vector<real>& cell, const double& base, std::vector<real>& numder ) { int natoms = coordinates.size() / 3; real delta = sqrt(epsilon); - std::vector<Vector> pos(natoms); real bias=0; + std::vector<Vector> pos(natoms); real bias=0; std::vector<real> fake_forces( 3*natoms ), fake_virial(9); - for(int i=0;i<natoms;++i){ - for(unsigned j=0;j<3;++j) pos[i][j]=coordinates[3*i+j]; + for(int i=0; i<natoms; ++i) { + for(unsigned j=0; j<3; ++j) pos[i][j]=coordinates[3*i+j]; } - for(int i=0;i<natoms;++i){ - for(unsigned j=0;j<3;++j){ - pos[i][j]=pos[i][j]+delta; - p.cmd("setStepLong",&step); - p.cmd("setPositions",&pos[0][0]); - p.cmd("setForces",&fake_forces[0]); - p.cmd("setMasses",&masses[0]); - p.cmd("setCharges",&charges[0]); - p.cmd("setBox",&cell[0]); - p.cmd("setVirial",&fake_virial[0]); - p.cmd("prepareCalc"); - p.cmd("performCalcNoUpdate"); - p.cmd("getBias",&bias); - pos[i][j]=coordinates[3*i+j]; - numder[3*i+j] = (bias - base) / delta; - } + for(int i=0; i<natoms; ++i) { + for(unsigned j=0; j<3; ++j) { + pos[i][j]=pos[i][j]+delta; + p.cmd("setStepLong",&step); + p.cmd("setPositions",&pos[0][0]); + p.cmd("setForces",&fake_forces[0]); + p.cmd("setMasses",&masses[0]); + p.cmd("setCharges",&charges[0]); + p.cmd("setBox",&cell[0]); + p.cmd("setVirial",&fake_virial[0]); + p.cmd("prepareCalc"); + p.cmd("performCalcNoUpdate"); + p.cmd("getBias",&bias); + pos[i][j]=coordinates[3*i+j]; + numder[3*i+j] = (bias - base) / delta; + } } // Create the cell Tensor box( cell[0], cell[1], cell[2], cell[3], cell[4], cell[5], cell[6], cell[7], cell[8] ); // And the virial - Pbc pbc; pbc.setBox( box ); Tensor nvirial; - for(unsigned i=0;i<3;i++) for(unsigned k=0;k<3;k++){ - double arg0=box(i,k); - for(int j=0;j<natoms;++j) pos[j]=pbc.realToScaled( pos[j] ); - cell[3*i+k]=box(i,k)=box(i,k)+delta; pbc.setBox(box); - for(int j=0;j<natoms;j++) pos[j]=pbc.scaledToReal( pos[j] ); - p.cmd("setStepLong",&step); - p.cmd("setPositions",&pos[0][0]); - p.cmd("setForces",&fake_forces[0]); - p.cmd("setMasses",&masses[0]); - p.cmd("setCharges",&charges[0]); - p.cmd("setBox",&cell[0]); - p.cmd("setVirial",&fake_virial[0]); - p.cmd("prepareCalc"); - p.cmd("performCalcNoUpdate"); - p.cmd("getBias",&bias); - cell[3*i+k]=box(i,k)=arg0; pbc.setBox(box); - for(int j=0;j<natoms;j++) for(unsigned n=0;n<3;++n) pos[j][n]=coordinates[3*j+n]; - nvirial(i,k) = ( bias - base ) / delta; - } + Pbc pbc; pbc.setBox( box ); Tensor nvirial; + for(unsigned i=0; i<3; i++) for(unsigned k=0; k<3; k++) { + double arg0=box(i,k); + for(int j=0; j<natoms; ++j) pos[j]=pbc.realToScaled( pos[j] ); + cell[3*i+k]=box(i,k)=box(i,k)+delta; pbc.setBox(box); + for(int j=0; j<natoms; j++) pos[j]=pbc.scaledToReal( pos[j] ); + p.cmd("setStepLong",&step); + p.cmd("setPositions",&pos[0][0]); + p.cmd("setForces",&fake_forces[0]); + p.cmd("setMasses",&masses[0]); + p.cmd("setCharges",&charges[0]); + p.cmd("setBox",&cell[0]); + p.cmd("setVirial",&fake_virial[0]); + p.cmd("prepareCalc"); + p.cmd("performCalcNoUpdate"); + p.cmd("getBias",&bias); + cell[3*i+k]=box(i,k)=arg0; pbc.setBox(box); + for(int j=0; j<natoms; j++) for(unsigned n=0; n<3; ++n) pos[j][n]=coordinates[3*j+n]; + nvirial(i,k) = ( bias - base ) / delta; + } nvirial=-matmul(box.transpose(),nvirial); - for(unsigned i=0;i<3;i++) for(unsigned k=0;k<3;k++) numder[3*natoms+3*i+k] = nvirial(i,k); + for(unsigned i=0; i<3; i++) for(unsigned k=0; k<3; k++) numder[3*natoms+3*i+k] = nvirial(i,k); -} +} } } diff --git a/src/cltools/DriverDouble.cpp b/src/cltools/DriverDouble.cpp index 88f0386b3..4ef9a46d2 100644 --- a/src/cltools/DriverDouble.cpp +++ b/src/cltools/DriverDouble.cpp @@ -23,7 +23,7 @@ #include "Driver.cpp" namespace PLMD { -namespace cltools{ +namespace cltools { // We instantiate here the template version of Driver so as // to accelerate parallel compilation. diff --git a/src/cltools/DriverFloat.cpp b/src/cltools/DriverFloat.cpp index 00088a672..d410866da 100644 --- a/src/cltools/DriverFloat.cpp +++ b/src/cltools/DriverFloat.cpp @@ -23,7 +23,7 @@ #include "Driver.cpp" namespace PLMD { -namespace cltools{ +namespace cltools { // We instantiate here the template version of Driver so as // to accelerate parallel compilation. @@ -32,7 +32,7 @@ typedef Driver<float> DriverFloat; /// Specialized version template<> -string Driver<float>::description()const{ return "analyze trajectories with plumed (single precision version)"; } +string Driver<float>::description()const { return "analyze trajectories with plumed (single precision version)"; } PLUMED_REGISTER_CLTOOL(DriverFloat,"driver-float") diff --git a/src/cltools/GenTemplate.cpp b/src/cltools/GenTemplate.cpp index 7ac49aa37..bce33af84 100644 --- a/src/cltools/GenTemplate.cpp +++ b/src/cltools/GenTemplate.cpp @@ -32,7 +32,7 @@ using namespace std; namespace PLMD { -namespace cltools{ +namespace cltools { //+PLUMEDOC TOOLS gentemplate /* @@ -48,26 +48,26 @@ The following generates template input for the action DISTANCE. \verbatim plumed gentemplate --action DISTANCE \endverbatim - + */ //+ENDPLUMEDOC class GenTemplate: -public CLTool + public CLTool { public: static void registerKeywords( Keywords& keys ); explicit GenTemplate(const CLToolOptions& co ); int main(FILE* in, FILE*out,Communicator& pc); - string description()const{ + string description()const { return "print out a template input for a particular action"; } }; PLUMED_REGISTER_CLTOOL(GenTemplate,"gentemplate") -void GenTemplate::registerKeywords( Keywords& keys ){ +void GenTemplate::registerKeywords( Keywords& keys ) { CLTool::registerKeywords( keys ); keys.add("optional","--action","print the template for this particular action"); keys.addFlag("--list",false,"print a list of the available actions"); @@ -75,32 +75,32 @@ void GenTemplate::registerKeywords( Keywords& keys ){ } GenTemplate::GenTemplate(const CLToolOptions& co ): -CLTool(co) + CLTool(co) { inputdata=commandline; } -int GenTemplate::main(FILE* in, FILE*out,Communicator& pc){ +int GenTemplate::main(FILE* in, FILE*out,Communicator& pc) { - std::string action; - bool list_templates=false; - parseFlag("--list",list_templates); + std::string action; + bool list_templates=false; + parseFlag("--list",list_templates); - if(list_templates) { - std::cerr<<actionRegister()<<"\n"; - return 0; - } else if(parse("--action",action)) { - bool include_optional; - parseFlag("--include-optional",include_optional); - if( !actionRegister().printTemplate(action,include_optional) ){ - error("there is no registered action named " + action); - return 1; - } - } else return 1; + if(list_templates) { + std::cerr<<actionRegister()<<"\n"; + return 0; + } else if(parse("--action",action)) { + bool include_optional; + parseFlag("--include-optional",include_optional); + if( !actionRegister().printTemplate(action,include_optional) ) { + error("there is no registered action named " + action); + return 1; + } + } else return 1; - return 0; + return 0; } } diff --git a/src/cltools/Info.cpp b/src/cltools/Info.cpp index 486d2f70b..fe9c1e192 100644 --- a/src/cltools/Info.cpp +++ b/src/cltools/Info.cpp @@ -30,7 +30,7 @@ using namespace std; namespace PLMD { -namespace cltools{ +namespace cltools { //+PLUMEDOC TOOLS info /* @@ -50,20 +50,20 @@ plumed info --root //+ENDPLUMEDOC class Info: -public CLTool + public CLTool { public: static void registerKeywords( Keywords& keys ); explicit Info(const CLToolOptions& co ); int main(FILE* in, FILE*out,Communicator& pc); - string description()const{ + string description()const { return "provide informations about plumed"; } }; PLUMED_REGISTER_CLTOOL(Info,"info") -void Info::registerKeywords( Keywords& keys ){ +void Info::registerKeywords( Keywords& keys ) { CLTool::registerKeywords( keys ); keys.addFlag("--configuration",false,"prints the configuration file"); keys.addFlag("--root",false,"print the location of the root directory for the plumed source"); @@ -75,31 +75,31 @@ void Info::registerKeywords( Keywords& keys ){ } Info::Info(const CLToolOptions& co ): -CLTool(co) + CLTool(co) { inputdata=commandline; } -int Info::main(FILE* in, FILE*out,Communicator& pc){ - - bool printconfiguration; parseFlag("--configuration",printconfiguration); - bool printroot; parseFlag("--root",printroot); - bool printuserdoc; parseFlag("--user-doc",printuserdoc); - bool printdeveloperdoc; parseFlag("--developer-doc",printdeveloperdoc); - bool printversion; parseFlag("--version",printversion); - bool printlongversion; parseFlag("--long-version",printlongversion); - bool printgitversion; parseFlag("--git-version",printgitversion); - if(printroot) fprintf(out,"%s\n",config::getPlumedRoot().c_str()); - if(printconfiguration) fprintf(out,"%s",config::getMakefile().c_str()); - std::string userdoc=config::getPlumedHtmldir()+"/user-doc/html/index.html"; - std::string developerdoc=config::getPlumedHtmldir()+"/developer-doc/html/index.html"; - if(printuserdoc) fprintf(out,"%s\n",userdoc.c_str()); - if(printdeveloperdoc) fprintf(out,"%s\n",developerdoc.c_str()); - if(printversion) fprintf(out,"%s\n",config::getVersion().c_str()); - if(printlongversion) fprintf(out,"%s\n",config::getVersionLong().c_str()); - if(printgitversion) fprintf(out,"%s\n",config::getVersionGit().c_str()); - - return 0; +int Info::main(FILE* in, FILE*out,Communicator& pc) { + + bool printconfiguration; parseFlag("--configuration",printconfiguration); + bool printroot; parseFlag("--root",printroot); + bool printuserdoc; parseFlag("--user-doc",printuserdoc); + bool printdeveloperdoc; parseFlag("--developer-doc",printdeveloperdoc); + bool printversion; parseFlag("--version",printversion); + bool printlongversion; parseFlag("--long-version",printlongversion); + bool printgitversion; parseFlag("--git-version",printgitversion); + if(printroot) fprintf(out,"%s\n",config::getPlumedRoot().c_str()); + if(printconfiguration) fprintf(out,"%s",config::getMakefile().c_str()); + std::string userdoc=config::getPlumedHtmldir()+"/user-doc/html/index.html"; + std::string developerdoc=config::getPlumedHtmldir()+"/developer-doc/html/index.html"; + if(printuserdoc) fprintf(out,"%s\n",userdoc.c_str()); + if(printdeveloperdoc) fprintf(out,"%s\n",developerdoc.c_str()); + if(printversion) fprintf(out,"%s\n",config::getVersion().c_str()); + if(printlongversion) fprintf(out,"%s\n",config::getVersionLong().c_str()); + if(printgitversion) fprintf(out,"%s\n",config::getVersionGit().c_str()); + + return 0; } diff --git a/src/cltools/Manual.cpp b/src/cltools/Manual.cpp index f940092df..4df53a696 100644 --- a/src/cltools/Manual.cpp +++ b/src/cltools/Manual.cpp @@ -32,11 +32,11 @@ using namespace std; namespace PLMD { -namespace cltools{ +namespace cltools { //+PLUMEDOC TOOLS manual /* -manual is a tool that you can use to construct the manual page for +manual is a tool that you can use to construct the manual page for a particular action The manual constructed by this action is in html. In all probability you will never need to use this @@ -49,52 +49,52 @@ The following generates the html manual for the action DISTANCE. \verbatim plumed manual --action DISTANCE \endverbatim - + */ //+ENDPLUMEDOC class Manual: -public CLTool + public CLTool { public: static void registerKeywords( Keywords& keys ); explicit Manual(const CLToolOptions& co ); int main(FILE* in, FILE*out,Communicator& pc); - string description()const{ + string description()const { return "print out a description of the keywords for an action in html"; } }; PLUMED_REGISTER_CLTOOL(Manual,"manual") -void Manual::registerKeywords( Keywords& keys ){ +void Manual::registerKeywords( Keywords& keys ) { CLTool::registerKeywords( keys ); keys.add("compulsory","--action","print the manual for this particular action"); keys.addFlag("--vim",false,"print the keywords in vim syntax"); } Manual::Manual(const CLToolOptions& co ): -CLTool(co) + CLTool(co) { inputdata=commandline; } -int Manual::main(FILE* in, FILE*out,Communicator& pc){ - - std::string action; - if( !parse("--action",action) ) return 1; - std::cerr<<"LIST OF DOCUMENTED ACTIONS:\n"; - std::cerr<<actionRegister()<<"\n"; - std::cerr<<"LIST OF DOCUMENTED COMMAND LINE TOOLS:\n"; - std::cerr<<cltoolRegister()<<"\n\n"; - bool vimout; parseFlag("--vim",vimout); - if( !actionRegister().printManual(action,vimout) && !cltoolRegister().printManual(action) ){ - fprintf(stderr,"specified action is not registered\n"); - return 1; - } - - return 0; +int Manual::main(FILE* in, FILE*out,Communicator& pc) { + + std::string action; + if( !parse("--action",action) ) return 1; + std::cerr<<"LIST OF DOCUMENTED ACTIONS:\n"; + std::cerr<<actionRegister()<<"\n"; + std::cerr<<"LIST OF DOCUMENTED COMMAND LINE TOOLS:\n"; + std::cerr<<cltoolRegister()<<"\n\n"; + bool vimout; parseFlag("--vim",vimout); + if( !actionRegister().printManual(action,vimout) && !cltoolRegister().printManual(action) ) { + fprintf(stderr,"specified action is not registered\n"); + return 1; + } + + return 0; } } // End of namespace diff --git a/src/cltools/SimpleMD.cpp b/src/cltools/SimpleMD.cpp index 975566dd2..d94f89b8f 100644 --- a/src/cltools/SimpleMD.cpp +++ b/src/cltools/SimpleMD.cpp @@ -31,15 +31,15 @@ using namespace std; -namespace PLMD{ -namespace cltools{ +namespace PLMD { +namespace cltools { //+PLUMEDOC TOOLS simplemd /* simplemd allows one to do molecular dynamics on systems of Lennard-Jones atoms. The input to simplemd is spcified in an input file. Configurations are input and -output in xyz format. The input file should contain one directive per line. +output in xyz format. The input file should contain one directive per line. The directives available are as follows: \par Examples @@ -74,469 +74,469 @@ plumed simplemd --help //+ENDPLUMEDOC class SimpleMD: -public PLMD::CLTool + public PLMD::CLTool { - string description()const{ + string description()const { return "run lj code"; } -bool write_positions_first; -bool write_statistics_first; -int write_statistics_last_time_reopened; -FILE* write_statistics_fp; + bool write_positions_first; + bool write_statistics_first; + int write_statistics_last_time_reopened; + FILE* write_statistics_fp; public: -static void registerKeywords( Keywords& keys ){ - keys.add("compulsory","nstep","The number of steps of dynamics you want to run"); - keys.add("compulsory","temperature","NVE","the temperature at which you wish to run the simulation in LJ units"); - keys.add("compulsory","friction","off","The friction (in LJ units) for the langevin thermostat that is used to keep the temperature constant"); - keys.add("compulsory","tstep","0.005","the integration timestep in LJ units"); - keys.add("compulsory","inputfile","An xyz file containing the initial configuration of the system"); - keys.add("compulsory","forcecutoff","2.5",""); - keys.add("compulsory","listcutoff","3.0",""); - keys.add("compulsory","outputfile","An output xyz file containing the final configuration of the system"); - keys.add("compulsory","nconfig","10","The frequency with which to write configurations to the trajectory file followed by the name of the trajectory file"); - keys.add("compulsory","nstat","1","The frequency with which to write the statistics to the statistics file followed by the name of the statistics file"); - keys.add("compulsory","maxneighbours","10000","The maximum number of neighbours an atom can have"); - keys.add("compulsory","idum","0","The random number seed"); - keys.add("compulsory","ndim","3","The dimensionality of the system (some interesting LJ clusters are two dimensional)"); - keys.add("compulsory","wrapatoms","false","If true, atomic coordinates are written wrapped in minimal cell"); -} + static void registerKeywords( Keywords& keys ) { + keys.add("compulsory","nstep","The number of steps of dynamics you want to run"); + keys.add("compulsory","temperature","NVE","the temperature at which you wish to run the simulation in LJ units"); + keys.add("compulsory","friction","off","The friction (in LJ units) for the langevin thermostat that is used to keep the temperature constant"); + keys.add("compulsory","tstep","0.005","the integration timestep in LJ units"); + keys.add("compulsory","inputfile","An xyz file containing the initial configuration of the system"); + keys.add("compulsory","forcecutoff","2.5",""); + keys.add("compulsory","listcutoff","3.0",""); + keys.add("compulsory","outputfile","An output xyz file containing the final configuration of the system"); + keys.add("compulsory","nconfig","10","The frequency with which to write configurations to the trajectory file followed by the name of the trajectory file"); + keys.add("compulsory","nstat","1","The frequency with which to write the statistics to the statistics file followed by the name of the statistics file"); + keys.add("compulsory","maxneighbours","10000","The maximum number of neighbours an atom can have"); + keys.add("compulsory","idum","0","The random number seed"); + keys.add("compulsory","ndim","3","The dimensionality of the system (some interesting LJ clusters are two dimensional)"); + keys.add("compulsory","wrapatoms","false","If true, atomic coordinates are written wrapped in minimal cell"); + } -explicit SimpleMD( const CLToolOptions& co ) : - CLTool(co), - write_positions_first(true), - write_statistics_first(true), - write_statistics_last_time_reopened(0), - write_statistics_fp(NULL) -{ - inputdata=ifile; -} + explicit SimpleMD( const CLToolOptions& co ) : + CLTool(co), + write_positions_first(true), + write_statistics_first(true), + write_statistics_last_time_reopened(0), + write_statistics_fp(NULL) + { + inputdata=ifile; + } private: -void -read_input(double& temperature, - double& tstep, - double& friction, - double& forcecutoff, - double& listcutoff, - int& nstep, - int& nconfig, - int& nstat, - bool& wrapatoms, - string& inputfile, - string& outputfile, - string& trajfile, - string& statfile, - int& maxneighbours, - int& ndim, - int& idum) -{ - - // Read everything from input file - char buffer1[256]; - std::string tempstr; parse("temperature",tempstr); - if( tempstr!="NVE" ) Tools::convert(tempstr,temperature); - parse("tstep",tstep); - std::string frictionstr; parse("friction",frictionstr); - if( tempstr!="NVE" ){ - if(frictionstr=="off"){ fprintf(stderr,"Specify friction for thermostat\n"); exit(1); } - Tools::convert(frictionstr,friction); - } - parse("forcecutoff",forcecutoff); - parse("listcutoff",listcutoff); - parse("nstep",nstep); - parse("maxneighbours",maxneighbours); - parse("idum",idum); - - // Read in stuff with sanity checks - parse("inputfile",inputfile); - if(inputfile.length()==0){ + void + read_input(double& temperature, + double& tstep, + double& friction, + double& forcecutoff, + double& listcutoff, + int& nstep, + int& nconfig, + int& nstat, + bool& wrapatoms, + string& inputfile, + string& outputfile, + string& trajfile, + string& statfile, + int& maxneighbours, + int& ndim, + int& idum) + { + + // Read everything from input file + char buffer1[256]; + std::string tempstr; parse("temperature",tempstr); + if( tempstr!="NVE" ) Tools::convert(tempstr,temperature); + parse("tstep",tstep); + std::string frictionstr; parse("friction",frictionstr); + if( tempstr!="NVE" ) { + if(frictionstr=="off") { fprintf(stderr,"Specify friction for thermostat\n"); exit(1); } + Tools::convert(frictionstr,friction); + } + parse("forcecutoff",forcecutoff); + parse("listcutoff",listcutoff); + parse("nstep",nstep); + parse("maxneighbours",maxneighbours); + parse("idum",idum); + + // Read in stuff with sanity checks + parse("inputfile",inputfile); + if(inputfile.length()==0) { fprintf(stderr,"Specify input file\n"); exit(1); - } - parse("outputfile",outputfile); - if(outputfile.length()==0){ + } + parse("outputfile",outputfile); + if(outputfile.length()==0) { fprintf(stderr,"Specify output file\n"); exit(1); - } - std::string nconfstr; parse("nconfig",nconfstr); - sscanf(nconfstr.c_str(),"%100d %255s",&nconfig,buffer1); - trajfile=buffer1; - if(trajfile.length()==0){ + } + std::string nconfstr; parse("nconfig",nconfstr); + sscanf(nconfstr.c_str(),"%100d %255s",&nconfig,buffer1); + trajfile=buffer1; + if(trajfile.length()==0) { fprintf(stderr,"Specify traj file\n"); exit(1); - } - std::string nstatstr; parse("nstat",nstatstr); - sscanf(nstatstr.c_str(),"%100d %255s",&nstat,buffer1); - statfile=buffer1; - if(statfile.length()==0){ + } + std::string nstatstr; parse("nstat",nstatstr); + sscanf(nstatstr.c_str(),"%100d %255s",&nstat,buffer1); + statfile=buffer1; + if(statfile.length()==0) { fprintf(stderr,"Specify stat file\n"); exit(1); - } - parse("ndim",ndim); - if(ndim<1 || ndim>3){ + } + parse("ndim",ndim); + if(ndim<1 || ndim>3) { fprintf(stderr,"ndim should be 1,2 or 3\n"); exit(1); + } + std::string w; + parse("wrapatoms",w); + wrapatoms=false; + if(w.length()>0 && (w[0]=='T' || w[0]=='t')) wrapatoms=true; } - std::string w; - parse("wrapatoms",w); - wrapatoms=false; - if(w.length()>0 && (w[0]=='T' || w[0]=='t')) wrapatoms=true; -} -void read_natoms(const string & inputfile,int & natoms){ + void read_natoms(const string & inputfile,int & natoms) { // read the number of atoms in file "input.xyz" - FILE* fp=fopen(inputfile.c_str(),"r"); - if(!fp){ - fprintf(stderr,"ERROR: file %s not found\n",inputfile.c_str()); - exit(1); + FILE* fp=fopen(inputfile.c_str(),"r"); + if(!fp) { + fprintf(stderr,"ERROR: file %s not found\n",inputfile.c_str()); + exit(1); + } + fscanf(fp,"%1000d",&natoms); + fclose(fp); } - fscanf(fp,"%1000d",&natoms); - fclose(fp); -} -void read_positions(const string& inputfile,int natoms,vector<Vector>& positions,double cell[3]){ + void read_positions(const string& inputfile,int natoms,vector<Vector>& positions,double cell[3]) { // read positions and cell from a file called inputfile // natoms (input variable) and number of atoms in the file should be consistent - FILE* fp=fopen(inputfile.c_str(),"r"); - if(!fp){ - fprintf(stderr,"ERROR: file %s not found\n",inputfile.c_str()); - exit(1); - } - char buffer[256]; - char atomname[256]; - fgets(buffer,256,fp); - fscanf(fp,"%1000lf %1000lf %1000lf",&cell[0],&cell[1],&cell[2]); - for(int i=0;i<natoms;i++){ - fscanf(fp,"%255s %1000lf %1000lf %1000lf",atomname,&positions[i][0],&positions[i][1],&positions[i][2]); + FILE* fp=fopen(inputfile.c_str(),"r"); + if(!fp) { + fprintf(stderr,"ERROR: file %s not found\n",inputfile.c_str()); + exit(1); + } + char buffer[256]; + char atomname[256]; + fgets(buffer,256,fp); + fscanf(fp,"%1000lf %1000lf %1000lf",&cell[0],&cell[1],&cell[2]); + for(int i=0; i<natoms; i++) { + fscanf(fp,"%255s %1000lf %1000lf %1000lf",atomname,&positions[i][0],&positions[i][1],&positions[i][2]); // note: atomname is read but not used + } + fclose(fp); } - fclose(fp); -} -void randomize_velocities(const int natoms,const int ndim,const double temperature,const vector<double>&masses,vector<Vector>& velocities,Random&random){ + void randomize_velocities(const int natoms,const int ndim,const double temperature,const vector<double>&masses,vector<Vector>& velocities,Random&random) { // randomize the velocities according to the temperature - for(int iatom=0;iatom<natoms;iatom++) for(int i=0;i<ndim;i++) - velocities[iatom][i]=sqrt(temperature/masses[iatom])*random.Gaussian(); -} + for(int iatom=0; iatom<natoms; iatom++) for(int i=0; i<ndim; i++) + velocities[iatom][i]=sqrt(temperature/masses[iatom])*random.Gaussian(); + } -void pbc(const double cell[3],const Vector & vin,Vector & vout){ + void pbc(const double cell[3],const Vector & vin,Vector & vout) { // apply periodic boundary condition to a vector - for(int i=0;i<3;i++){ - vout[i]=vin[i]-floor(vin[i]/cell[i]+0.5)*cell[i]; + for(int i=0; i<3; i++) { + vout[i]=vin[i]-floor(vin[i]/cell[i]+0.5)*cell[i]; + } } -} -void check_list(const int natoms,const vector<Vector>& positions,const vector<Vector>&positions0,const double listcutoff, - const double forcecutoff,bool & recompute) -{ + void check_list(const int natoms,const vector<Vector>& positions,const vector<Vector>&positions0,const double listcutoff, + const double forcecutoff,bool & recompute) + { // check if the neighbour list have to be recomputed - Vector displacement; // displacement from positions0 to positions - double delta2; // square of the 'skin' thickness - recompute=false; - delta2=(0.5*(listcutoff-forcecutoff))*(0.5*(listcutoff-forcecutoff)); + Vector displacement; // displacement from positions0 to positions + double delta2; // square of the 'skin' thickness + recompute=false; + delta2=(0.5*(listcutoff-forcecutoff))*(0.5*(listcutoff-forcecutoff)); // if ANY atom moved more than half of the skin thickness, recompute is set to .true. - for(int iatom=0;iatom<natoms;iatom++){ - for(int k=0;k<3;k++) displacement[k]=positions[iatom][k]-positions0[iatom][k]; - double s=0.0; - for(int k=0;k<3;k++) s+=displacement[k]*displacement[k]; - if(s>delta2) recompute=true; + for(int iatom=0; iatom<natoms; iatom++) { + for(int k=0; k<3; k++) displacement[k]=positions[iatom][k]-positions0[iatom][k]; + double s=0.0; + for(int k=0; k<3; k++) s+=displacement[k]*displacement[k]; + if(s>delta2) recompute=true; + } } -} -void compute_list(const int natoms,const int listsize,const vector<Vector>& positions,const double cell[3],const double listcutoff, - vector<int>& point,vector<int>& list){ + void compute_list(const int natoms,const int listsize,const vector<Vector>& positions,const double cell[3],const double listcutoff, + vector<int>& point,vector<int>& list) { // see Allen-Tildesey for a definition of point and list - Vector distance; // distance of the two atoms - Vector distance_pbc; // minimum-image distance of the two atoms - double listcutoff2; // squared list cutoff - listcutoff2=listcutoff*listcutoff; - point[0]=0; - for(int iatom=0;iatom<natoms-1;iatom++){ - point[iatom+1]=point[iatom]; - for(int jatom=iatom+1;jatom<natoms;jatom++){ - for(int k=0;k<3;k++) distance[k]=positions[iatom][k]-positions[jatom][k]; - pbc(cell,distance,distance_pbc); + Vector distance; // distance of the two atoms + Vector distance_pbc; // minimum-image distance of the two atoms + double listcutoff2; // squared list cutoff + listcutoff2=listcutoff*listcutoff; + point[0]=0; + for(int iatom=0; iatom<natoms-1; iatom++) { + point[iatom+1]=point[iatom]; + for(int jatom=iatom+1; jatom<natoms; jatom++) { + for(int k=0; k<3; k++) distance[k]=positions[iatom][k]-positions[jatom][k]; + pbc(cell,distance,distance_pbc); // if the interparticle distance is larger than the cutoff, skip - double d2=0; for(int k=0;k<3;k++) d2+=distance_pbc[k]*distance_pbc[k]; - if(d2>listcutoff2)continue; - if(point[iatom+1]>listsize){ + double d2=0; for(int k=0; k<3; k++) d2+=distance_pbc[k]*distance_pbc[k]; + if(d2>listcutoff2)continue; + if(point[iatom+1]>listsize) { // too many neighbours - fprintf(stderr,"%s","Verlet list size exceeded\n"); - fprintf(stderr,"%s","Increase maxneighbours\n"); - exit(1); + fprintf(stderr,"%s","Verlet list size exceeded\n"); + fprintf(stderr,"%s","Increase maxneighbours\n"); + exit(1); + } + list[point[iatom+1]]=jatom; + point[iatom+1]++; } - list[point[iatom+1]]=jatom; - point[iatom+1]++; } } -} -void compute_forces(const int natoms,const int listsize,const vector<Vector>& positions,const double cell[3], - double forcecutoff,const vector<int>& point,const vector<int>& list,vector<Vector>& forces,double & engconf) -{ - Vector distance; // distance of the two atoms - Vector distance_pbc; // minimum-image distance of the two atoms - double distance_pbc2; // squared minimum-image distance - double forcecutoff2; // squared force cutoff - Vector f; // force - double engcorrection; // energy necessary shift the potential avoiding discontinuities - - forcecutoff2=forcecutoff*forcecutoff; - engconf=0.0; - for(int i=0;i<natoms;i++)for(int k=0;k<3;k++) forces[i][k]=0.0; - engcorrection=4.0*(1.0/pow(forcecutoff2,6.0)-1.0/pow(forcecutoff2,3)); - for(int iatom=0;iatom<natoms-1;iatom++){ - for(int jlist=point[iatom];jlist<point[iatom+1];jlist++){ - int jatom=list[jlist]; - for(int k=0;k<3;k++) distance[k]=positions[iatom][k]-positions[jatom][k]; - pbc(cell,distance,distance_pbc); - distance_pbc2=0.0; for(int k=0;k<3;k++) distance_pbc2+=distance_pbc[k]*distance_pbc[k]; + void compute_forces(const int natoms,const int listsize,const vector<Vector>& positions,const double cell[3], + double forcecutoff,const vector<int>& point,const vector<int>& list,vector<Vector>& forces,double & engconf) + { + Vector distance; // distance of the two atoms + Vector distance_pbc; // minimum-image distance of the two atoms + double distance_pbc2; // squared minimum-image distance + double forcecutoff2; // squared force cutoff + Vector f; // force + double engcorrection; // energy necessary shift the potential avoiding discontinuities + + forcecutoff2=forcecutoff*forcecutoff; + engconf=0.0; + for(int i=0; i<natoms; i++)for(int k=0; k<3; k++) forces[i][k]=0.0; + engcorrection=4.0*(1.0/pow(forcecutoff2,6.0)-1.0/pow(forcecutoff2,3)); + for(int iatom=0; iatom<natoms-1; iatom++) { + for(int jlist=point[iatom]; jlist<point[iatom+1]; jlist++) { + int jatom=list[jlist]; + for(int k=0; k<3; k++) distance[k]=positions[iatom][k]-positions[jatom][k]; + pbc(cell,distance,distance_pbc); + distance_pbc2=0.0; for(int k=0; k<3; k++) distance_pbc2+=distance_pbc[k]*distance_pbc[k]; // if the interparticle distance is larger than the cutoff, skip - if(distance_pbc2>forcecutoff2) continue; - double distance_pbc6=distance_pbc2*distance_pbc2*distance_pbc2; - double distance_pbc8=distance_pbc6*distance_pbc2; - double distance_pbc12=distance_pbc6*distance_pbc6; - double distance_pbc14=distance_pbc12*distance_pbc2; - engconf+=4.0*(1.0/distance_pbc12 - 1.0/distance_pbc6) - engcorrection; - for(int k=0;k<3;k++) f[k]=2.0*distance_pbc[k]*4.0*(6.0/distance_pbc14-3.0/distance_pbc8); + if(distance_pbc2>forcecutoff2) continue; + double distance_pbc6=distance_pbc2*distance_pbc2*distance_pbc2; + double distance_pbc8=distance_pbc6*distance_pbc2; + double distance_pbc12=distance_pbc6*distance_pbc6; + double distance_pbc14=distance_pbc12*distance_pbc2; + engconf+=4.0*(1.0/distance_pbc12 - 1.0/distance_pbc6) - engcorrection; + for(int k=0; k<3; k++) f[k]=2.0*distance_pbc[k]*4.0*(6.0/distance_pbc14-3.0/distance_pbc8); // same force on the two atoms, with opposite sign: - for(int k=0;k<3;k++) forces[iatom][k]+=f[k]; - for(int k=0;k<3;k++) forces[jatom][k]-=f[k]; + for(int k=0; k<3; k++) forces[iatom][k]+=f[k]; + for(int k=0; k<3; k++) forces[jatom][k]-=f[k]; + } } } -} -void compute_engkin(const int natoms,const vector<double>& masses,const vector<Vector>& velocities,double & engkin) -{ + void compute_engkin(const int natoms,const vector<double>& masses,const vector<Vector>& velocities,double & engkin) + { // calculate the kinetic energy from the velocities - engkin=0.0; - for(int iatom=0;iatom<natoms;iatom++)for(int k=0;k<3;k++){ - engkin+=0.5*masses[iatom]*velocities[iatom][k]*velocities[iatom][k]; + engkin=0.0; + for(int iatom=0; iatom<natoms; iatom++)for(int k=0; k<3; k++) { + engkin+=0.5*masses[iatom]*velocities[iatom][k]*velocities[iatom][k]; + } } -} -void thermostat(const int natoms,const int ndim,const vector<double>& masses,const double dt,const double friction, - const double temperature,vector<Vector>& velocities,double & engint,Random & random){ + void thermostat(const int natoms,const int ndim,const vector<double>& masses,const double dt,const double friction, + const double temperature,vector<Vector>& velocities,double & engint,Random & random) { // Langevin thermostat, implemented as decribed in Bussi and Parrinello, Phys. Rev. E (2007) // it is a linear combination of old velocities and new, randomly chosen, velocity, // with proper coefficients - double c1=exp(-friction*dt); - for(int iatom=0;iatom<natoms;iatom++){ - double c2=sqrt((1.0-c1*c1)*temperature/masses[iatom]); - for(int i=0;i<ndim;i++){ - engint+=0.5*masses[iatom]*velocities[iatom][i]*velocities[iatom][i]; - velocities[iatom][i]=c1*velocities[iatom][i]+c2*random.Gaussian(); - engint-=0.5*masses[iatom]*velocities[iatom][i]*velocities[iatom][i]; + double c1=exp(-friction*dt); + for(int iatom=0; iatom<natoms; iatom++) { + double c2=sqrt((1.0-c1*c1)*temperature/masses[iatom]); + for(int i=0; i<ndim; i++) { + engint+=0.5*masses[iatom]*velocities[iatom][i]*velocities[iatom][i]; + velocities[iatom][i]=c1*velocities[iatom][i]+c2*random.Gaussian(); + engint-=0.5*masses[iatom]*velocities[iatom][i]*velocities[iatom][i]; + } } } -} -void write_positions(const string& trajfile,int natoms,const vector<Vector>& positions,const double cell[3],const bool wrapatoms) -{ + void write_positions(const string& trajfile,int natoms,const vector<Vector>& positions,const double cell[3],const bool wrapatoms) + { // write positions on file trajfile // positions are appended at the end of the file - Vector pos; - FILE*fp; - if(write_positions_first){ - fp=fopen(trajfile.c_str(),"w"); - write_positions_first=false; - } else { - fp=fopen(trajfile.c_str(),"a"); - } - fprintf(fp,"%d\n",natoms); - fprintf(fp,"%f %f %f\n",cell[0],cell[1],cell[2]); - for(int iatom=0;iatom<natoms;iatom++){ + Vector pos; + FILE*fp; + if(write_positions_first) { + fp=fopen(trajfile.c_str(),"w"); + write_positions_first=false; + } else { + fp=fopen(trajfile.c_str(),"a"); + } + fprintf(fp,"%d\n",natoms); + fprintf(fp,"%f %f %f\n",cell[0],cell[1],cell[2]); + for(int iatom=0; iatom<natoms; iatom++) { // usually, it is better not to apply pbc here, so that diffusion // is more easily calculated from a trajectory file: - if(wrapatoms) pbc(cell,positions[iatom],pos); - else for(int k=0;k<3;k++) pos[k]=positions[iatom][k]; - fprintf(fp,"Ar %10.7f %10.7f %10.7f\n",pos[0],pos[1],pos[2]); + if(wrapatoms) pbc(cell,positions[iatom],pos); + else for(int k=0; k<3; k++) pos[k]=positions[iatom][k]; + fprintf(fp,"Ar %10.7f %10.7f %10.7f\n",pos[0],pos[1],pos[2]); + } + fclose(fp); } - fclose(fp); -} -void write_final_positions(const string& outputfile,int natoms,const vector<Vector>& positions,const double cell[3],const bool wrapatoms) -{ + void write_final_positions(const string& outputfile,int natoms,const vector<Vector>& positions,const double cell[3],const bool wrapatoms) + { // write positions on file outputfile - Vector pos; - FILE*fp; - fp=fopen(outputfile.c_str(),"w"); - fprintf(fp,"%d\n",natoms); - fprintf(fp,"%f %f %f\n",cell[0],cell[1],cell[2]); - for(int iatom=0;iatom<natoms;iatom++){ + Vector pos; + FILE*fp; + fp=fopen(outputfile.c_str(),"w"); + fprintf(fp,"%d\n",natoms); + fprintf(fp,"%f %f %f\n",cell[0],cell[1],cell[2]); + for(int iatom=0; iatom<natoms; iatom++) { // usually, it is better not to apply pbc here, so that diffusion // is more easily calculated from a trajectory file: - if(wrapatoms) pbc(cell,positions[iatom],pos); - else for(int k=0;k<3;k++) pos[k]=positions[iatom][k]; - fprintf(fp,"Ar %10.7f %10.7f %10.7f\n",pos[0],pos[1],pos[2]); + if(wrapatoms) pbc(cell,positions[iatom],pos); + else for(int k=0; k<3; k++) pos[k]=positions[iatom][k]; + fprintf(fp,"Ar %10.7f %10.7f %10.7f\n",pos[0],pos[1],pos[2]); + } + fclose(fp); } - fclose(fp); -} -void write_statistics(const string & statfile,const int istep,const double tstep, - const int natoms,const int ndim,const double engkin,const double engconf,const double engint){ + void write_statistics(const string & statfile,const int istep,const double tstep, + const int natoms,const int ndim,const double engkin,const double engconf,const double engint) { // write statistics on file statfile - if(write_statistics_first){ + if(write_statistics_first) { // first time this routine is called, open the file - write_statistics_fp=fopen(statfile.c_str(),"w"); - write_statistics_first=false; - } - if(istep-write_statistics_last_time_reopened>100){ + write_statistics_fp=fopen(statfile.c_str(),"w"); + write_statistics_first=false; + } + if(istep-write_statistics_last_time_reopened>100) { // every 100 steps, reopen the file to flush the buffer - fclose(write_statistics_fp); - write_statistics_fp=fopen(statfile.c_str(),"a"); - write_statistics_last_time_reopened=istep; + fclose(write_statistics_fp); + write_statistics_fp=fopen(statfile.c_str(),"a"); + write_statistics_last_time_reopened=istep; + } + fprintf(write_statistics_fp,"%d %f %f %f %f %f\n",istep,istep*tstep,2.0*engkin/double(ndim*natoms),engconf,engkin+engconf,engkin+engconf+engint); } - fprintf(write_statistics_fp,"%d %f %f %f %f %f\n",istep,istep*tstep,2.0*engkin/double(ndim*natoms),engconf,engkin+engconf,engkin+engconf+engint); -} -virtual int main(FILE* in,FILE*out,PLMD::Communicator& pc){ - int natoms; // number of atoms - vector<Vector> positions; // atomic positions - vector<Vector> velocities; // velocities - vector<double> masses; // masses - vector<Vector> forces; // forces - double cell[3]; // cell size - double cell9[3][3]; // cell size + virtual int main(FILE* in,FILE*out,PLMD::Communicator& pc) { + int natoms; // number of atoms + vector<Vector> positions; // atomic positions + vector<Vector> velocities; // velocities + vector<double> masses; // masses + vector<Vector> forces; // forces + double cell[3]; // cell size + double cell9[3][3]; // cell size // neighbour list variables // see Allen and Tildesey book for details - int listsize; // size of the list array - vector<int> list; // neighbour list - vector<int> point; // pointer to neighbour list - vector<Vector> positions0; // reference atomic positions, i.e. positions when the neighbour list + int listsize; // size of the list array + vector<int> list; // neighbour list + vector<int> point; // pointer to neighbour list + vector<Vector> positions0; // reference atomic positions, i.e. positions when the neighbour list // input parameters // all of them have a reasonable default value, set in read_input() - double tstep; // simulation timestep - double temperature; // temperature - double friction; // friction for Langevin dynamics (for NVE, use 0) - double listcutoff; // cutoff for neighbour list - double forcecutoff; // cutoff for forces - int nstep; // number of steps - int nconfig; // stride for output of configurations - int nstat; // stride for output of statistics - int maxneighbour; // maximum average number of neighbours per atom - int ndim; // dimensionality of the system (1, 2, or 3) - int idum; // seed - int plumedWantsToStop; // stop flag - bool wrapatoms; // if true, atomic coordinates are written wrapped in minimal cell - string inputfile; // name of file with starting configuration (xyz) - string outputfile; // name of file with final configuration (xyz) - string trajfile; // name of the trajectory file (xyz) - string statfile; // name of the file with statistics - - double engkin; // kinetic energy - double engconf; // configurational energy - double engint; // integral for conserved energy in Langevin dynamics - - bool recompute_list; // control if the neighbour list have to be recomputed - - Random random; // random numbers stream - - PLMD::Plumed* plumed=NULL; + double tstep; // simulation timestep + double temperature; // temperature + double friction; // friction for Langevin dynamics (for NVE, use 0) + double listcutoff; // cutoff for neighbour list + double forcecutoff; // cutoff for forces + int nstep; // number of steps + int nconfig; // stride for output of configurations + int nstat; // stride for output of statistics + int maxneighbour; // maximum average number of neighbours per atom + int ndim; // dimensionality of the system (1, 2, or 3) + int idum; // seed + int plumedWantsToStop; // stop flag + bool wrapatoms; // if true, atomic coordinates are written wrapped in minimal cell + string inputfile; // name of file with starting configuration (xyz) + string outputfile; // name of file with final configuration (xyz) + string trajfile; // name of the trajectory file (xyz) + string statfile; // name of the file with statistics + + double engkin; // kinetic energy + double engconf; // configurational energy + double engint; // integral for conserved energy in Langevin dynamics + + bool recompute_list; // control if the neighbour list have to be recomputed + + Random random; // random numbers stream + + PLMD::Plumed* plumed=NULL; // Commenting the next line it is possible to switch-off plumed - plumed=new PLMD::Plumed; + plumed=new PLMD::Plumed; - if(plumed){ - int s=sizeof(double); - plumed->cmd("setRealPrecision",&s); - } + if(plumed) { + int s=sizeof(double); + plumed->cmd("setRealPrecision",&s); + } - read_input(temperature,tstep,friction,forcecutoff, - listcutoff,nstep,nconfig,nstat, - wrapatoms,inputfile,outputfile,trajfile,statfile, - maxneighbour,ndim,idum); + read_input(temperature,tstep,friction,forcecutoff, + listcutoff,nstep,nconfig,nstat, + wrapatoms,inputfile,outputfile,trajfile,statfile, + maxneighbour,ndim,idum); // number of atoms is read from file inputfile - read_natoms(inputfile,natoms); + read_natoms(inputfile,natoms); // write the parameters in output so they can be checked - fprintf(out,"%s %s\n","Starting configuration :",inputfile.c_str()); - fprintf(out,"%s %s\n","Final configuration :",outputfile.c_str()); - fprintf(out,"%s %d\n","Number of atoms :",natoms); - fprintf(out,"%s %f\n","Temperature :",temperature); - fprintf(out,"%s %f\n","Time step :",tstep); - fprintf(out,"%s %f\n","Friction :",friction); - fprintf(out,"%s %f\n","Cutoff for forces :",forcecutoff); - fprintf(out,"%s %f\n","Cutoff for neighbour list :",listcutoff); - fprintf(out,"%s %d\n","Number of steps :",nstep); - fprintf(out,"%s %d\n","Stride for trajectory :",nconfig); - fprintf(out,"%s %s\n","Trajectory file :",trajfile.c_str()); - fprintf(out,"%s %d\n","Stride for statistics :",nstat); - fprintf(out,"%s %s\n","Statistics file :",statfile.c_str()); - fprintf(out,"%s %d\n","Max average number of neighbours :",maxneighbour); - fprintf(out,"%s %d\n","Dimensionality :",ndim); - fprintf(out,"%s %d\n","Seed :",idum); - fprintf(out,"%s %s\n","Are atoms wrapped on output? :",(wrapatoms?"T":"F")); + fprintf(out,"%s %s\n","Starting configuration :",inputfile.c_str()); + fprintf(out,"%s %s\n","Final configuration :",outputfile.c_str()); + fprintf(out,"%s %d\n","Number of atoms :",natoms); + fprintf(out,"%s %f\n","Temperature :",temperature); + fprintf(out,"%s %f\n","Time step :",tstep); + fprintf(out,"%s %f\n","Friction :",friction); + fprintf(out,"%s %f\n","Cutoff for forces :",forcecutoff); + fprintf(out,"%s %f\n","Cutoff for neighbour list :",listcutoff); + fprintf(out,"%s %d\n","Number of steps :",nstep); + fprintf(out,"%s %d\n","Stride for trajectory :",nconfig); + fprintf(out,"%s %s\n","Trajectory file :",trajfile.c_str()); + fprintf(out,"%s %d\n","Stride for statistics :",nstat); + fprintf(out,"%s %s\n","Statistics file :",statfile.c_str()); + fprintf(out,"%s %d\n","Max average number of neighbours :",maxneighbour); + fprintf(out,"%s %d\n","Dimensionality :",ndim); + fprintf(out,"%s %d\n","Seed :",idum); + fprintf(out,"%s %s\n","Are atoms wrapped on output? :",(wrapatoms?"T":"F")); // Setting the seed - random.setSeed(idum); + random.setSeed(idum); // Since each atom pair is counted once, the total number of pairs // will be half of the number of neighbours times the number of atoms - listsize=maxneighbour*natoms/2; + listsize=maxneighbour*natoms/2; // allocation of dynamical arrays - positions.resize(natoms); - positions0.resize(natoms); - velocities.resize(natoms); - forces.resize(natoms); - masses.resize(natoms); - point.resize(natoms); - list.resize(listsize); + positions.resize(natoms); + positions0.resize(natoms); + velocities.resize(natoms); + forces.resize(natoms); + masses.resize(natoms); + point.resize(natoms); + list.resize(listsize); // masses are hard-coded to 1 - for(int i=0;i<natoms;++i) masses[i]=1.0; + for(int i=0; i<natoms; ++i) masses[i]=1.0; // energy integral initialized to 0 - engint=0.0; + engint=0.0; // positions are read from file inputfile - read_positions(inputfile,natoms,positions,cell); + read_positions(inputfile,natoms,positions,cell); // velocities are randomized according to temperature - randomize_velocities(natoms,ndim,temperature,masses,velocities,random); - - if(plumed){ - plumed->cmd("setNoVirial"); - plumed->cmd("setNatoms",&natoms); - plumed->cmd("setMDEngine","simpleMD"); - plumed->cmd("setTimestep",&tstep); - plumed->cmd("setPlumedDat","plumed.dat"); - int pversion=0; - plumed->cmd("getApiVersion",&pversion); + randomize_velocities(natoms,ndim,temperature,masses,velocities,random); + + if(plumed) { + plumed->cmd("setNoVirial"); + plumed->cmd("setNatoms",&natoms); + plumed->cmd("setMDEngine","simpleMD"); + plumed->cmd("setTimestep",&tstep); + plumed->cmd("setPlumedDat","plumed.dat"); + int pversion=0; + plumed->cmd("getApiVersion",&pversion); // setting kbT is only implemented with api>1 // even if not necessary in principle in SimpleMD (which is part of plumed) // we leave the check here as a reference - if(pversion>1){ + if(pversion>1) { plumed->cmd("setKbT",&temperature); } - plumed->cmd("init"); - } + plumed->cmd("init"); + } // neighbour list are computed, and reference positions are saved - compute_list(natoms,listsize,positions,cell,listcutoff,point,list); + compute_list(natoms,listsize,positions,cell,listcutoff,point,list); - fprintf(out,"List size: %d\n",point[natoms-1]); - for(int iatom=0;iatom<natoms;++iatom) for(int k=0;k<3;++k) positions0[iatom][k]=positions[iatom][k]; + fprintf(out,"List size: %d\n",point[natoms-1]); + for(int iatom=0; iatom<natoms; ++iatom) for(int k=0; k<3; ++k) positions0[iatom][k]=positions[iatom][k]; // forces are computed before starting md - compute_forces(natoms,listsize,positions,cell,forcecutoff,point,list,forces,engconf); + compute_forces(natoms,listsize,positions,cell,forcecutoff,point,list,forces,engconf); // remove forces if ndim<3 - if(ndim<3) - for(int iatom=0;iatom<natoms;++iatom) for(int k=ndim;k<3;++k) forces[iatom][k]=0.0; + if(ndim<3) + for(int iatom=0; iatom<natoms; ++iatom) for(int k=ndim; k<3; ++k) forces[iatom][k]=0.0; // here is the main md loop // Langevin thermostat is applied before and after a velocity-Verlet integrator @@ -549,69 +549,69 @@ virtual int main(FILE* in,FILE*out,PLMD::Communicator& pc){ // update velocities // thermostat // (eventually dump output informations) - for(int istep=0;istep<nstep;istep++){ - thermostat(natoms,ndim,masses,0.5*tstep,friction,temperature,velocities,engint,random); + for(int istep=0; istep<nstep; istep++) { + thermostat(natoms,ndim,masses,0.5*tstep,friction,temperature,velocities,engint,random); - for(int iatom=0;iatom<natoms;iatom++) for(int k=0;k<3;k++) - velocities[iatom][k]+=forces[iatom][k]*0.5*tstep/masses[iatom]; + for(int iatom=0; iatom<natoms; iatom++) for(int k=0; k<3; k++) + velocities[iatom][k]+=forces[iatom][k]*0.5*tstep/masses[iatom]; - for(int iatom=0;iatom<natoms;iatom++) for(int k=0;k<3;k++) - positions[iatom][k]+=velocities[iatom][k]*tstep; + for(int iatom=0; iatom<natoms; iatom++) for(int k=0; k<3; k++) + positions[iatom][k]+=velocities[iatom][k]*tstep; // a check is performed to decide whether to recalculate the neighbour list - check_list(natoms,positions,positions0,listcutoff,forcecutoff,recompute_list); - if(recompute_list){ - compute_list(natoms,listsize,positions,cell,listcutoff,point,list); - for(int iatom=0;iatom<natoms;++iatom) for(int k=0;k<3;++k) positions0[iatom][k]=positions[iatom][k]; - fprintf(out,"Neighbour list recomputed at step %d\n",istep); - fprintf(out,"List size: %d\n",point[natoms-1]); - } - - compute_forces(natoms,listsize,positions,cell,forcecutoff,point,list,forces,engconf); + check_list(natoms,positions,positions0,listcutoff,forcecutoff,recompute_list); + if(recompute_list) { + compute_list(natoms,listsize,positions,cell,listcutoff,point,list); + for(int iatom=0; iatom<natoms; ++iatom) for(int k=0; k<3; ++k) positions0[iatom][k]=positions[iatom][k]; + fprintf(out,"Neighbour list recomputed at step %d\n",istep); + fprintf(out,"List size: %d\n",point[natoms-1]); + } - if(plumed){ - int istepplusone=istep+1; - plumedWantsToStop=0; - for(int i=0;i<3;i++)for(int k=0;k<3;k++) cell9[i][k]=0.0; - for(int i=0;i<3;i++) cell9[i][i]=cell[i]; - plumed->cmd("setStep",&istepplusone); - plumed->cmd("setMasses",&masses[0]); - plumed->cmd("setForces",&forces[0]); - plumed->cmd("setEnergy",&engconf); - plumed->cmd("setPositions",&positions[0]); - plumed->cmd("setBox",cell9); - plumed->cmd("setStopFlag",&plumedWantsToStop); - plumed->cmd("calc"); - if(plumedWantsToStop) nstep=istep; - } + compute_forces(natoms,listsize,positions,cell,forcecutoff,point,list,forces,engconf); + + if(plumed) { + int istepplusone=istep+1; + plumedWantsToStop=0; + for(int i=0; i<3; i++)for(int k=0; k<3; k++) cell9[i][k]=0.0; + for(int i=0; i<3; i++) cell9[i][i]=cell[i]; + plumed->cmd("setStep",&istepplusone); + plumed->cmd("setMasses",&masses[0]); + plumed->cmd("setForces",&forces[0]); + plumed->cmd("setEnergy",&engconf); + plumed->cmd("setPositions",&positions[0]); + plumed->cmd("setBox",cell9); + plumed->cmd("setStopFlag",&plumedWantsToStop); + plumed->cmd("calc"); + if(plumedWantsToStop) nstep=istep; + } // remove forces if ndim<3 - if(ndim<3) - for(int iatom=0;iatom<natoms;++iatom) for(int k=ndim;k<3;++k) forces[iatom][k]=0.0; + if(ndim<3) + for(int iatom=0; iatom<natoms; ++iatom) for(int k=ndim; k<3; ++k) forces[iatom][k]=0.0; - for(int iatom=0;iatom<natoms;iatom++) for(int k=0;k<3;k++) - velocities[iatom][k]+=forces[iatom][k]*0.5*tstep/masses[iatom]; + for(int iatom=0; iatom<natoms; iatom++) for(int k=0; k<3; k++) + velocities[iatom][k]+=forces[iatom][k]*0.5*tstep/masses[iatom]; - thermostat(natoms,ndim,masses,0.5*tstep,friction,temperature,velocities,engint,random); + thermostat(natoms,ndim,masses,0.5*tstep,friction,temperature,velocities,engint,random); // kinetic energy is calculated - compute_engkin(natoms,masses,velocities,engkin); + compute_engkin(natoms,masses,velocities,engkin); // eventually, write positions and statistics - if((istep+1)%nconfig==0) write_positions(trajfile,natoms,positions,cell,wrapatoms); - if((istep+1)%nstat==0) write_statistics(statfile,istep+1,tstep,natoms,ndim,engkin,engconf,engint); + if((istep+1)%nconfig==0) write_positions(trajfile,natoms,positions,cell,wrapatoms); + if((istep+1)%nstat==0) write_statistics(statfile,istep+1,tstep,natoms,ndim,engkin,engconf,engint); - } + } // write final positions - write_final_positions(outputfile,natoms,positions,cell,wrapatoms); + write_final_positions(outputfile,natoms,positions,cell,wrapatoms); // close the statistic file if it was open: - if(write_statistics_fp) fclose(write_statistics_fp); + if(write_statistics_fp) fclose(write_statistics_fp); - if(plumed) delete plumed; + if(plumed) delete plumed; - return 0; -} + return 0; + } }; diff --git a/src/cltools/SumHills.cpp b/src/cltools/SumHills.cpp index ace183adb..ffdc51874 100644 --- a/src/cltools/SumHills.cpp +++ b/src/cltools/SumHills.cpp @@ -40,106 +40,106 @@ using namespace std; namespace PLMD { namespace cltools { -//+PLUMEDOC TOOLS sum_hills +//+PLUMEDOC TOOLS sum_hills /* -sum_hills is a tool that allows one to to use plumed to post-process an existing hills/colvar file +sum_hills is a tool that allows one to to use plumed to post-process an existing hills/colvar file \par Examples -a typical case is about the integration of a hills file: +a typical case is about the integration of a hills file: \verbatim -plumed sum_hills --hills PATHTOMYHILLSFILE +plumed sum_hills --hills PATHTOMYHILLSFILE \endverbatim -The default name for the output file will be fes.dat -Note that starting from this version plumed will automatically detect the -number of the variables you have and their periodicity. +The default name for the output file will be fes.dat +Note that starting from this version plumed will automatically detect the +number of the variables you have and their periodicity. Additionally, if you use flexible hills (multivariate gaussians), plumed will understand it from the HILLS file. -now sum_hills tool accepts als multiple files that will be integrated one after the other +now sum_hills tool accepts als multiple files that will be integrated one after the other \verbatim -plumed sum_hills --hills PATHTOMYHILLSFILE1,PATHTOMYHILLSFILE2,PATHTOMYHILLSFILE3 +plumed sum_hills --hills PATHTOMYHILLSFILE1,PATHTOMYHILLSFILE2,PATHTOMYHILLSFILE3 \endverbatim if you want to integrate out some variable you do \verbatim -plumed sum_hills --hills PATHTOMYHILLSFILE --idw t1 --kt 0.6 +plumed sum_hills --hills PATHTOMYHILLSFILE --idw t1 --kt 0.6 \endverbatim where with --idw you define the variables that you want all the others will be integrated out. --kt defines the temperature of the system in energy units. -(be consistent with the units you have in your hills: plumed will not check this for you) +(be consistent with the units you have in your hills: plumed will not check this for you) If you need more variables then you may use a comma separated syntax \verbatim -plumed sum_hills --hills PATHTOMYHILLSFILE --idw t1,t2 --kt 0.6 +plumed sum_hills --hills PATHTOMYHILLSFILE --idw t1,t2 --kt 0.6 \endverbatim -You can define the output grid only with the number of bins you want +You can define the output grid only with the number of bins you want while min/max will be detected for you \verbatim -plumed sum_hills --bin 99,99 --hills PATHTOMYHILLSFILE +plumed sum_hills --bin 99,99 --hills PATHTOMYHILLSFILE \endverbatim or full grid specification \verbatim -plumed sum_hills --bin 99,99 --min -pi,-pi --max pi,pi --hills PATHTOMYHILLSFILE +plumed sum_hills --bin 99,99 --min -pi,-pi --max pi,pi --hills PATHTOMYHILLSFILE \endverbatim You can of course use numbers instead of -pi/pi. -You can use a --stride keyword to have a dump each bunch of hills you read +You can use a --stride keyword to have a dump each bunch of hills you read \verbatim -plumed sum_hills --stride 300 --hills PATHTOMYHILLSFILE +plumed sum_hills --stride 300 --hills PATHTOMYHILLSFILE \endverbatim - -You can also have, in case of welltempered metadynamics, only the negative + +You can also have, in case of welltempered metadynamics, only the negative bias instead of the free energy through the keyword --negbias \verbatim -plumed sum_hills --negbias --hills PATHTOMYHILLSFILE +plumed sum_hills --negbias --hills PATHTOMYHILLSFILE \endverbatim -Here the default name will be negativebias.dat +Here the default name will be negativebias.dat -From time to time you might need to use HILLS or a COLVAR file -as it was just a simple set of points from which you want to build +From time to time you might need to use HILLS or a COLVAR file +as it was just a simple set of points from which you want to build a free energy by using -(1/beta)log(P) then you use --histo \verbatim -plumed sum_hills --histo PATHTOMYCOLVARORHILLSFILE --sigma 0.2,0.2 --kt 0.6 +plumed sum_hills --histo PATHTOMYCOLVARORHILLSFILE --sigma 0.2,0.2 --kt 0.6 \endverbatim in this case you need a --kt to do the reweighting and then you -need also some width (with the --sigma keyword) for the histogram calculation (actually will be done with +need also some width (with the --sigma keyword) for the histogram calculation (actually will be done with gaussians, so it will be a continuous histogram) Here the default output will be histo.dat. Note that also here you can have multiple input files separated by a comma. -Additionally, if you want to do histogram and hills from the same file you can do as this +Additionally, if you want to do histogram and hills from the same file you can do as this \verbatim -plumed sum_hills --hills --histo PATHTOMYCOLVARORHILLSFILE --sigma 0.2,0.2 --kt 0.6 +plumed sum_hills --hills --histo PATHTOMYCOLVARORHILLSFILE --sigma 0.2,0.2 --kt 0.6 \endverbatim -The two files can be eventually the same +The two files can be eventually the same -Another interesting thing one can do is monitor the difference in blocks as a metadynamics goes on. -When the bias deposited is constant over the whole domain one can consider to be at convergence. -This can be done with the --nohistory keyword +Another interesting thing one can do is monitor the difference in blocks as a metadynamics goes on. +When the bias deposited is constant over the whole domain one can consider to be at convergence. +This can be done with the --nohistory keyword \verbatim -plumed sum_hills --stride 300 --hills PATHTOMYHILLSFILE --nohistory +plumed sum_hills --stride 300 --hills PATHTOMYHILLSFILE --nohistory \endverbatim -and similarly one can do the same for an histogram file +and similarly one can do the same for an histogram file \verbatim -plumed sum_hills --histo PATHTOMYCOLVARORHILLSFILE --sigma 0.2,0.2 --kt 0.6 --nohistory +plumed sum_hills --histo PATHTOMYCOLVARORHILLSFILE --sigma 0.2,0.2 --kt 0.6 --nohistory \endverbatim just to check the hypothetical free energy calculated in single blocks of time during a simulation @@ -148,20 +148,20 @@ and not in a cumulative way Output format can be controlled via the --fmt field \verbatim -plumed sum_hills --hills PATHTOMYHILLSFILE --fmt %8.3f +plumed sum_hills --hills PATHTOMYHILLSFILE --fmt %8.3f \endverbatim -where here we chose a float with length of 8 and 3 digits +where here we chose a float with length of 8 and 3 digits -The output can be named in a arbitrary way : +The output can be named in a arbitrary way : \verbatim -plumed sum_hills --hills PATHTOMYHILLSFILE --outfile myfes.dat +plumed sum_hills --hills PATHTOMYHILLSFILE --outfile myfes.dat \endverbatim will produce a file myfes.dat which contains the free energy. -If you use stride, this keyword is the suffix +If you use stride, this keyword is the suffix \verbatim plumed sum_hills --hills PATHTOMYHILLSFILE --outfile myfes_ --stride 100 @@ -169,16 +169,16 @@ plumed sum_hills --hills PATHTOMYHILLSFILE --outfile myfes_ --stride 100 will produce myfes_0.dat, myfes_1.dat, myfes_2.dat etc. -The same is true for the output coming from histogram +The same is true for the output coming from histogram \verbatim plumed sum_hills --histo HILLS --kt 2.5 --sigma 0.01 --outhisto myhisto.dat \endverbatim is producing a file myhisto.dat -while, when using stride, this is the suffix +while, when using stride, this is the suffix \verbatim -plumed sum_hills --histo HILLS --kt 2.5 --sigma 0.01 --outhisto myhisto_ --stride 100 +plumed sum_hills --histo HILLS --kt 2.5 --sigma 0.01 --outhisto myhisto_ --stride 100 \endverbatim that gives myhisto_0.dat, myhisto_1.dat, myhisto_3.dat etc.. @@ -193,11 +193,11 @@ public: int main(FILE* in,FILE*out,Communicator& pc); string description()const; /// find a list of variables present, if they are periodic and which is the period -/// return false if the file does not exist +/// return false if the file does not exist static bool findCvsAndPeriodic(std::string filename, std::vector< std::vector <std::string> > &cvs,std::vector<std::string> &pmin,std::vector<std::string> &pmax, bool &multivariate, string &lowI_, string &uppI_); }; -void CLToolSumHills::registerKeywords( Keywords& keys ){ +void CLToolSumHills::registerKeywords( Keywords& keys ) { CLTool::registerKeywords( keys ); keys.addFlag("--help-debug",false,"print special options that can be used to create regtests"); keys.add("optional","--hills","specify the name of the hills file"); @@ -219,21 +219,21 @@ void CLToolSumHills::registerKeywords( Keywords& keys ){ } CLToolSumHills::CLToolSumHills(const CLToolOptions& co ): -CLTool(co) + CLTool(co) { - inputdata=commandline; + inputdata=commandline; } -string CLToolSumHills::description()const{ return "sum the hills with plumed"; } +string CLToolSumHills::description()const { return "sum the hills with plumed"; } + +int CLToolSumHills::main(FILE* in,FILE*out,Communicator& pc) { -int CLToolSumHills::main(FILE* in,FILE*out,Communicator& pc){ - -// Read the hills input file name - vector<string> hillsFiles; +// Read the hills input file name + vector<string> hillsFiles; bool dohills; dohills=parseVector("--hills",hillsFiles); // Read the histogram file - vector<string> histoFiles; + vector<string> histoFiles; bool dohisto; dohisto=parseVector("--histo",histoFiles); @@ -243,44 +243,44 @@ int CLToolSumHills::main(FILE* in,FILE*out,Communicator& pc){ vector<string> vpmin; vector<string> vpmax; string lowI_, uppI_; - if(dohills){ - // parse it as it was a restart - bool vmultivariate; - findCvsAndPeriodic(hillsFiles[0], vcvs, vpmin, vpmax, vmultivariate, lowI_, uppI_); + if(dohills) { + // parse it as it was a restart + bool vmultivariate; + findCvsAndPeriodic(hillsFiles[0], vcvs, vpmin, vpmax, vmultivariate, lowI_, uppI_); } vector< vector<string> > hcvs; vector<string> hpmin; vector<string> hpmax; - - vector<std::string> sigma; - if(dohisto){ - bool hmultivariate; - findCvsAndPeriodic(histoFiles[0], hcvs, hpmin, hpmax, hmultivariate, lowI_, uppI_); - // here need also the vector of sigmas - parseVector("--sigma",sigma); - if(sigma.size()==0)plumed_merror("you should define --sigma vector when using histogram"); - lowI_=uppI_="-1."; // Interval is not use for histograms + + vector<std::string> sigma; + if(dohisto) { + bool hmultivariate; + findCvsAndPeriodic(histoFiles[0], hcvs, hpmin, hpmax, hmultivariate, lowI_, uppI_); + // here need also the vector of sigmas + parseVector("--sigma",sigma); + if(sigma.size()==0)plumed_merror("you should define --sigma vector when using histogram"); + lowI_=uppI_="-1."; // Interval is not use for histograms } - if(dohisto && dohills){ - plumed_massert(vcvs==hcvs,"variables for histogram and bias should have the same labels"); - plumed_massert(hpmin==vpmin,"variables for histogram and bias should have the same min for periodicity"); - plumed_massert(hpmax==vpmax,"variables for histogram and bias should have the same max for periodicity"); + if(dohisto && dohills) { + plumed_massert(vcvs==hcvs,"variables for histogram and bias should have the same labels"); + plumed_massert(hpmin==vpmin,"variables for histogram and bias should have the same min for periodicity"); + plumed_massert(hpmax==vpmax,"variables for histogram and bias should have the same max for periodicity"); } - // now put into a neutral vector - + // now put into a neutral vector + vector< vector<string> > cvs; vector<string> pmin; vector<string> pmax; - if(dohills){ + if(dohills) { cvs=vcvs; pmin=vpmin; pmax=vpmax; } - if(dohisto){ + if(dohisto) { cvs=hcvs; pmin=hpmin; pmax=hpmax; @@ -288,32 +288,32 @@ int CLToolSumHills::main(FILE* in,FILE*out,Communicator& pc){ // setup grids - unsigned grid_check=0; + unsigned grid_check=0; vector<std::string> gmin(cvs.size()); - if(parseVector("--min",gmin)){ - if(gmin.size()!=cvs.size() && gmin.size()!=0) plumed_merror("not enough values for --min"); - grid_check++; + if(parseVector("--min",gmin)) { + if(gmin.size()!=cvs.size() && gmin.size()!=0) plumed_merror("not enough values for --min"); + grid_check++; } vector<std::string> gmax(cvs.size() ); - if(parseVector("--max",gmax)){ - if(gmax.size()!=cvs.size() && gmax.size()!=0) plumed_merror("not enough values for --max"); - grid_check++; + if(parseVector("--max",gmax)) { + if(gmax.size()!=cvs.size() && gmax.size()!=0) plumed_merror("not enough values for --max"); + grid_check++; } vector<std::string> gbin(cvs.size()); - bool grid_has_bin; grid_has_bin=false; - if(parseVector("--bin",gbin)){ - if(gbin.size()!=cvs.size() && gbin.size()!=0) plumed_merror("not enough values for --bin"); - grid_has_bin=true; + bool grid_has_bin; grid_has_bin=false; + if(parseVector("--bin",gbin)) { + if(gbin.size()!=cvs.size() && gbin.size()!=0) plumed_merror("not enough values for --bin"); + grid_has_bin=true; } vector<std::string> gspacing(cvs.size()); - bool grid_has_spacing; grid_has_spacing=false; - if(parseVector("--spacing",gspacing)){ - if(gspacing.size()!=cvs.size() && gspacing.size()!=0) plumed_merror("not enough values for --spacing"); - grid_has_spacing=true; + bool grid_has_spacing; grid_has_spacing=false; + if(parseVector("--spacing",gspacing)) { + if(gspacing.size()!=cvs.size() && gspacing.size()!=0) plumed_merror("not enough values for --spacing"); + grid_has_spacing=true; } // allowed: no grids only bin - // not allowed: partial grid definition - plumed_massert( gmin.size()==gmax.size() && (gmin.size()==0 || gmin.size()==cvs.size() ) ,"you should specify --min and --max together with same number of components"); + // not allowed: partial grid definition + plumed_massert( gmin.size()==gmax.size() && (gmin.size()==0 || gmin.size()==cvs.size() ),"you should specify --min and --max together with same number of components"); @@ -321,99 +321,99 @@ int CLToolSumHills::main(FILE* in,FILE*out,Communicator& pc){ std::string ss; unsigned nn=1; ss="setNatoms"; - plumed.cmd(ss,&nn); - if(Communicator::initialized()) plumed.cmd("setMPIComm",&pc.Get_comm()); - plumed.cmd("init",&nn); - vector <bool> isdone(cvs.size(),false); - for(unsigned i=0;i<cvs.size();i++){ - if(!isdone[i]){ - isdone[i]=true; - std::vector<std::string> actioninput; - std::vector <unsigned> inds; - actioninput.push_back("FAKE"); - actioninput.push_back("ATOMS=1"); - actioninput.push_back("LABEL="+cvs[i][0]); - std::vector<std::string> comps, periods; - if(cvs[i].size()>1){comps.push_back(cvs[i][1]);inds.push_back(i);} - periods.push_back(pmin[i]);periods.push_back(pmax[i]); - for(unsigned j=i+1;j<cvs.size();j++){ - if(cvs[i][0]==cvs[j][0] && !isdone[j]){ - if(cvs[i].size()==1 || cvs[j].size()==1 )plumed_merror("you cannot have twice the same label and no components "); - if(cvs[j].size()>1){ - comps.push_back(cvs[j][1]); - periods.push_back(pmin[j]);periods.push_back(pmax[j]); - isdone[j]=true; inds.push_back(j); - } - } - - } - // drain all the components - std::string addme; - if(comps.size()>0){ - addme="COMPONENTS="; - for(unsigned i=0;i<comps.size()-1;i++)addme+=comps[i]+","; - addme+=comps.back(); - actioninput.push_back(addme); - } - // periodicity (always explicit here) - addme="PERIODIC="; - for(unsigned j=0;j<periods.size()-1;j++){ - addme+=periods[j]+","; - } - addme+=periods.back(); - actioninput.push_back(addme); - for(unsigned j=0;j<inds.size();j++){ - unsigned jj;jj=inds[j]; - if(grid_check==2){ - double gm; - double pm; - if(pmin[jj]!="none"){ - Tools::convert(gmin[jj],gm); - Tools::convert(pmin[jj],pm); - if( gm<pm ){ - plumed_merror("Periodicity issue : GRID_MIN value ( "+gmin[jj]+" ) is less than periodicity in HILLS file in "+cvs[jj][0]+ " ( "+pmin[jj]+" ) "); - } - } - if(pmax[jj]!="none"){ - Tools::convert(gmax[jj],gm); - Tools::convert(pmax[jj],pm); - if( gm>pm ){ - plumed_merror("Periodicity issue : GRID_MAX value ( "+gmax[jj]+" ) is more than periodicity in HILLS file in "+cvs[jj][0]+ " ( "+pmax[jj]+" ) "); - } - } - } - } + plumed.cmd(ss,&nn); + if(Communicator::initialized()) plumed.cmd("setMPIComm",&pc.Get_comm()); + plumed.cmd("init",&nn); + vector <bool> isdone(cvs.size(),false); + for(unsigned i=0; i<cvs.size(); i++) { + if(!isdone[i]) { + isdone[i]=true; + std::vector<std::string> actioninput; + std::vector <unsigned> inds; + actioninput.push_back("FAKE"); + actioninput.push_back("ATOMS=1"); + actioninput.push_back("LABEL="+cvs[i][0]); + std::vector<std::string> comps, periods; + if(cvs[i].size()>1) {comps.push_back(cvs[i][1]); inds.push_back(i);} + periods.push_back(pmin[i]); periods.push_back(pmax[i]); + for(unsigned j=i+1; j<cvs.size(); j++) { + if(cvs[i][0]==cvs[j][0] && !isdone[j]) { + if(cvs[i].size()==1 || cvs[j].size()==1 )plumed_merror("you cannot have twice the same label and no components "); + if(cvs[j].size()>1) { + comps.push_back(cvs[j][1]); + periods.push_back(pmin[j]); periods.push_back(pmax[j]); + isdone[j]=true; inds.push_back(j); + } + } + + } + // drain all the components + std::string addme; + if(comps.size()>0) { + addme="COMPONENTS="; + for(unsigned i=0; i<comps.size()-1; i++)addme+=comps[i]+","; + addme+=comps.back(); + actioninput.push_back(addme); + } + // periodicity (always explicit here) + addme="PERIODIC="; + for(unsigned j=0; j<periods.size()-1; j++) { + addme+=periods[j]+","; + } + addme+=periods.back(); + actioninput.push_back(addme); + for(unsigned j=0; j<inds.size(); j++) { + unsigned jj; jj=inds[j]; + if(grid_check==2) { + double gm; + double pm; + if(pmin[jj]!="none") { + Tools::convert(gmin[jj],gm); + Tools::convert(pmin[jj],pm); + if( gm<pm ) { + plumed_merror("Periodicity issue : GRID_MIN value ( "+gmin[jj]+" ) is less than periodicity in HILLS file in "+cvs[jj][0]+ " ( "+pmin[jj]+" ) "); + } + } + if(pmax[jj]!="none") { + Tools::convert(gmax[jj],gm); + Tools::convert(pmax[jj],pm); + if( gm>pm ) { + plumed_merror("Periodicity issue : GRID_MAX value ( "+gmax[jj]+" ) is more than periodicity in HILLS file in "+cvs[jj][0]+ " ( "+pmax[jj]+" ) "); + } + } + } + } // for(unsigned i=0;i< actioninput.size();i++){ -// cerr<<"AA "<<actioninput[i]<<endl; +// cerr<<"AA "<<actioninput[i]<<endl; // } - plumed.readInputWords(actioninput); - } + plumed.readInputWords(actioninput); + } } unsigned ncv=cvs.size(); std::vector<std::string> actioninput; vector<std::string> idw; - // check if the variables to be used are correct - if(parseVector("--idw",idw)){ - for(unsigned i=0;i<idw.size();i++){ - bool found=false; - for(unsigned j=0;j<cvs.size();j++){ - if(cvs[j].size()>1){ - if(idw[i]==cvs[j][0]+"."+cvs[j][1])found=true; - }else{ - if(idw[i]==cvs[j][0])found=true; - } - } - if(!found)plumed_merror("variable "+idw[i]+" is not found in the bunch of cvs: revise your --idw option" ); - } - plumed_massert( idw.size()<=cvs.size() ,"the number of variables to be integrated should be at most equal to the total number of cvs "); - // in this case you neeed a beta factor! - } + // check if the variables to be used are correct + if(parseVector("--idw",idw)) { + for(unsigned i=0; i<idw.size(); i++) { + bool found=false; + for(unsigned j=0; j<cvs.size(); j++) { + if(cvs[j].size()>1) { + if(idw[i]==cvs[j][0]+"."+cvs[j][1])found=true; + } else { + if(idw[i]==cvs[j][0])found=true; + } + } + if(!found)plumed_merror("variable "+idw[i]+" is not found in the bunch of cvs: revise your --idw option" ); + } + plumed_massert( idw.size()<=cvs.size(),"the number of variables to be integrated should be at most equal to the total number of cvs "); + // in this case you neeed a beta factor! + } - std::string kt; kt=std::string("1.");// assign an arbitrary value just in case that idw.size()==cvs.size() + std::string kt; kt=std::string("1.");// assign an arbitrary value just in case that idw.size()==cvs.size() if ( dohisto || idw.size()!=0 ) { - plumed_massert(parse("--kt",kt),"if you make a dimensionality reduction (--idw) or a histogram (--histo) then you need to define --kt "); + plumed_massert(parse("--kt",kt),"if you make a dimensionality reduction (--idw) or a histogram (--histo) then you need to define --kt "); } std::string addme; @@ -423,70 +423,70 @@ int CLToolSumHills::main(FILE* in,FILE*out,Communicator& pc){ // set names std::string outfile; - if(parse("--outfile",outfile)){ - actioninput.push_back("OUTHILLS="+outfile); - } + if(parse("--outfile",outfile)) { + actioninput.push_back("OUTHILLS="+outfile); + } std::string outhisto; - if(parse("--outhisto",outhisto)){ - actioninput.push_back("OUTHISTO="+outhisto); - } + if(parse("--outhisto",outhisto)) { + actioninput.push_back("OUTHISTO="+outhisto); + } addme="ARG="; - for(unsigned i=0;i<(ncv-1);i++){ - if(cvs[i].size()==1){ - addme+=std::string(cvs[i][0])+","; - }else{ - addme+=std::string(cvs[i][0])+"."+std::string(cvs[i][1])+","; - } + for(unsigned i=0; i<(ncv-1); i++) { + if(cvs[i].size()==1) { + addme+=std::string(cvs[i][0])+","; + } else { + addme+=std::string(cvs[i][0])+"."+std::string(cvs[i][1])+","; + } } - if(cvs[ncv-1].size()==1){ - addme+=std::string(cvs[ncv-1][0]); - }else{ - addme+=std::string(cvs[ncv-1][0])+"."+std::string(cvs[ncv-1][1]); + if(cvs[ncv-1].size()==1) { + addme+=std::string(cvs[ncv-1][0]); + } else { + addme+=std::string(cvs[ncv-1][0])+"."+std::string(cvs[ncv-1][1]); } actioninput.push_back(addme); //for(unsigned i=0;i< actioninput.size();i++){ - // cerr<<"AA "<<actioninput[i]<<endl; + // cerr<<"AA "<<actioninput[i]<<endl; //} - if(dohills){ - addme="HILLSFILES="; for(unsigned i=0;i<hillsFiles.size()-1;i++)addme+=hillsFiles[i]+","; addme+=hillsFiles[hillsFiles.size()-1]; - actioninput.push_back(addme); - // set the grid + if(dohills) { + addme="HILLSFILES="; for(unsigned i=0; i<hillsFiles.size()-1; i++)addme+=hillsFiles[i]+","; addme+=hillsFiles[hillsFiles.size()-1]; + actioninput.push_back(addme); + // set the grid } - if(grid_check==2){ - addme="GRID_MAX="; for(unsigned i=0;i<(ncv-1);i++)addme+=gmax[i]+","; addme+=gmax[ncv-1]; - actioninput.push_back(addme); - addme="GRID_MIN="; for(unsigned i=0;i<(ncv-1);i++)addme+=gmin[i]+","; addme+=gmin[ncv-1]; - actioninput.push_back(addme); + if(grid_check==2) { + addme="GRID_MAX="; for(unsigned i=0; i<(ncv-1); i++)addme+=gmax[i]+","; addme+=gmax[ncv-1]; + actioninput.push_back(addme); + addme="GRID_MIN="; for(unsigned i=0; i<(ncv-1); i++)addme+=gmin[i]+","; addme+=gmin[ncv-1]; + actioninput.push_back(addme); } - if(grid_has_bin){ - addme="GRID_BIN="; for(unsigned i=0;i<(ncv-1);i++)addme+=gbin[i]+","; addme+=gbin[ncv-1]; - actioninput.push_back(addme); + if(grid_has_bin) { + addme="GRID_BIN="; for(unsigned i=0; i<(ncv-1); i++)addme+=gbin[i]+","; addme+=gbin[ncv-1]; + actioninput.push_back(addme); } - if(grid_has_spacing){ - addme="GRID_SPACING="; for(unsigned i=0;i<(ncv-1);i++)addme+=gspacing[i]+","; addme+=gspacing[ncv-1]; - actioninput.push_back(addme); + if(grid_has_spacing) { + addme="GRID_SPACING="; for(unsigned i=0; i<(ncv-1); i++)addme+=gspacing[i]+","; addme+=gspacing[ncv-1]; + actioninput.push_back(addme); } std::string stride; stride=""; - if(parse("--stride",stride)){ + if(parse("--stride",stride)) { actioninput.push_back("INITSTRIDE="+stride); - bool nohistory; + bool nohistory; parseFlag("--nohistory",nohistory); - if(nohistory){ - actioninput.push_back("NOHISTORY"); + if(nohistory) { + actioninput.push_back("NOHISTORY"); } } - bool mintozero; + bool mintozero; parseFlag("--mintozero",mintozero); - if(mintozero){ - actioninput.push_back("MINTOZERO"); + if(mintozero) { + actioninput.push_back("MINTOZERO"); } - if(idw.size()!=0){ - addme="PROJ="; - for(unsigned i=0;i<idw.size()-1;i++){addme+=idw[i]+",";} - addme+=idw.back(); - actioninput.push_back(addme); + if(idw.size()!=0) { + addme="PROJ="; + for(unsigned i=0; i<idw.size()-1; i++) {addme+=idw[i]+",";} + addme+=idw.back(); + actioninput.push_back(addme); } if(dohisto) { @@ -497,23 +497,23 @@ int CLToolSumHills::main(FILE* in,FILE*out,Communicator& pc){ } } - if(idw.size()!=0 || dohisto){ - actioninput.push_back("KT="+kt); - } - if(dohisto){ - addme="HISTOFILES="; for(unsigned i=0;i<histoFiles.size()-1;i++){addme+=histoFiles[i]+",";}addme+=histoFiles[histoFiles.size()-1]; - actioninput.push_back(addme); - - addme="HISTOSIGMA="; - for(unsigned i=0;i<sigma.size()-1;i++){addme+=sigma[i]+",";} - addme+=sigma.back(); - actioninput.push_back(addme); - } - + if(idw.size()!=0 || dohisto) { + actioninput.push_back("KT="+kt); + } + if(dohisto) { + addme="HISTOFILES="; for(unsigned i=0; i<histoFiles.size()-1; i++) {addme+=histoFiles[i]+",";} addme+=histoFiles[histoFiles.size()-1]; + actioninput.push_back(addme); + + addme="HISTOSIGMA="; + for(unsigned i=0; i<sigma.size()-1; i++) {addme+=sigma[i]+",";} + addme+=sigma.back(); + actioninput.push_back(addme); + } + bool negbias; parseFlag("--negbias",negbias); - if(negbias){ - actioninput.push_back("NEGBIAS"); + if(negbias) { + actioninput.push_back("NEGBIAS"); } if(lowI_!=uppI_) { @@ -521,101 +521,102 @@ int CLToolSumHills::main(FILE* in,FILE*out,Communicator& pc){ actioninput.push_back(addme); } - std::string fmt;fmt=""; + std::string fmt; fmt=""; parse("--fmt",fmt); if(fmt!="")actioninput.push_back("FMT="+fmt); // for(unsigned i=0;i< actioninput.size();i++){ -// cerr<<"AA "<<actioninput[i]<<endl; +// cerr<<"AA "<<actioninput[i]<<endl; // } plumed.readInputWords(actioninput); // if not a grid, then set it up automatically return 0; } -bool CLToolSumHills::findCvsAndPeriodic(std::string filename, std::vector< std::vector<std::string> > &cvs, std::vector<std::string> &pmin,std::vector<std::string> &pmax, bool &multivariate, string &lowI_, string &uppI_){ - IFile ifile; - ifile.allowIgnoredFields(); - std::vector<std::string> fields; - if(ifile.FileExist(filename)){ - cvs.clear(); pmin.clear(); pmax.clear(); - ifile.open(filename); - ifile.scanFieldList(fields); - bool before_sigma=true; - for(unsigned i=0;i<fields.size();i++){ - size_t pos = 0; - size_t founds,foundm,foundp; - //found=(fields[i].find("sigma_", pos) || fields[i].find("min_", pos) || fields[i].find("max_", pos) ) ; - founds=fields[i].find("sigma_", pos) ; - foundm=fields[i].find("min_", pos) ; - foundp=fields[i].find("max_", pos) ; - if (founds!=std::string::npos || foundm!=std::string::npos || foundp!=std::string::npos )before_sigma=false; - // cvs are after time and before sigmas - size_t found; - found=fields[i].find("time", pos); - if( found==std::string::npos && before_sigma){ - // separate the components - size_t dot=fields[i].find_first_of('.'); - std::vector<std::string> ss; - // this loop does not take into account repetitions - if(dot!=std::string::npos){ - std::string a=fields[i].substr(0,dot); - std::string name=fields[i].substr(dot+1); - ss.push_back(a); - ss.push_back(name); - cvs.push_back(ss); - }else{ - std::vector<std::string> ss; - ss.push_back(fields[i]); - cvs.push_back(ss); - } - //std::cerr<<"found variable number "<<cvs.size()<<" : "<<cvs.back()[0]<<std::endl; - //if((cvs.back()).size()!=1){ - // std::cerr<<"component "<<(cvs.back()).back()<<std::endl; - //} - // get periodicity - pmin.push_back("none"); - pmax.push_back("none"); - std::string mm; if((cvs.back()).size()>1){mm=cvs.back()[0]+"."+cvs.back()[1];}else{mm=cvs.back()[0];} - if(ifile.FieldExist("min_"+mm)){ - std::string val; - ifile.scanField("min_"+mm,val); - pmin[pmin.size()-1]=val; - // std::cerr<<"found min : "<<pmin.back()<<std::endl; - } - //std::cerr<<"found min : "<<pmin.back()<<std::endl; - if(ifile.FieldExist("max_"+mm)){ - std::string val; - ifile.scanField("max_"+mm,val); - pmax[pmax.size()-1]=val; - // std::cerr<<"found max : "<<pmax.back()<<std::endl; - } - //std::cerr<<"found max : "<<pmax.back()<<std::endl; - } - } - // is multivariate ??? - std::string sss; - multivariate=false; - if(ifile.FieldExist("multivariate")){; - ifile.scanField("multivariate",sss); - if(sss=="true"){ multivariate=true;} - else if(sss=="false"){ multivariate=false;} - } - // do interval? - if(ifile.FieldExist("lower_int")) { - ifile.scanField("lower_int",lowI_); - ifile.scanField("upper_int",uppI_); - } else { - lowI_="-1."; - uppI_="-1."; - } - ifile.scanField(); - ifile.close(); - return true; - }else { - return false; - } +bool CLToolSumHills::findCvsAndPeriodic(std::string filename, std::vector< std::vector<std::string> > &cvs, std::vector<std::string> &pmin,std::vector<std::string> &pmax, bool &multivariate, string &lowI_, string &uppI_) { + IFile ifile; + ifile.allowIgnoredFields(); + std::vector<std::string> fields; + if(ifile.FileExist(filename)) { + cvs.clear(); pmin.clear(); pmax.clear(); + ifile.open(filename); + ifile.scanFieldList(fields); + bool before_sigma=true; + for(unsigned i=0; i<fields.size(); i++) { + size_t pos = 0; + size_t founds,foundm,foundp; + //found=(fields[i].find("sigma_", pos) || fields[i].find("min_", pos) || fields[i].find("max_", pos) ) ; + founds=fields[i].find("sigma_", pos) ; + foundm=fields[i].find("min_", pos) ; + foundp=fields[i].find("max_", pos) ; + if (founds!=std::string::npos || foundm!=std::string::npos || foundp!=std::string::npos )before_sigma=false; + // cvs are after time and before sigmas + size_t found; + found=fields[i].find("time", pos); + if( found==std::string::npos && before_sigma) { + // separate the components + size_t dot=fields[i].find_first_of('.'); + std::vector<std::string> ss; + // this loop does not take into account repetitions + if(dot!=std::string::npos) { + std::string a=fields[i].substr(0,dot); + std::string name=fields[i].substr(dot+1); + ss.push_back(a); + ss.push_back(name); + cvs.push_back(ss); + } else { + std::vector<std::string> ss; + ss.push_back(fields[i]); + cvs.push_back(ss); + } + //std::cerr<<"found variable number "<<cvs.size()<<" : "<<cvs.back()[0]<<std::endl; + //if((cvs.back()).size()!=1){ + // std::cerr<<"component "<<(cvs.back()).back()<<std::endl; + //} + // get periodicity + pmin.push_back("none"); + pmax.push_back("none"); + std::string mm; if((cvs.back()).size()>1) {mm=cvs.back()[0]+"."+cvs.back()[1];} else {mm=cvs.back()[0];} + if(ifile.FieldExist("min_"+mm)) { + std::string val; + ifile.scanField("min_"+mm,val); + pmin[pmin.size()-1]=val; + // std::cerr<<"found min : "<<pmin.back()<<std::endl; + } + //std::cerr<<"found min : "<<pmin.back()<<std::endl; + if(ifile.FieldExist("max_"+mm)) { + std::string val; + ifile.scanField("max_"+mm,val); + pmax[pmax.size()-1]=val; + // std::cerr<<"found max : "<<pmax.back()<<std::endl; + } + //std::cerr<<"found max : "<<pmax.back()<<std::endl; + } + } + // is multivariate ??? + std::string sss; + multivariate=false; + if(ifile.FieldExist("multivariate")) { + ; + ifile.scanField("multivariate",sss); + if(sss=="true") { multivariate=true;} + else if(sss=="false") { multivariate=false;} + } + // do interval? + if(ifile.FieldExist("lower_int")) { + ifile.scanField("lower_int",lowI_); + ifile.scanField("upper_int",uppI_); + } else { + lowI_="-1."; + uppI_="-1."; + } + ifile.scanField(); + ifile.close(); + return true; + } else { + return false; + } } diff --git a/src/cltools/kT.cpp b/src/cltools/kT.cpp index f419f1aec..b1e25b4b8 100644 --- a/src/cltools/kT.cpp +++ b/src/cltools/kT.cpp @@ -33,15 +33,15 @@ using namespace std; namespace PLMD { -namespace cltools{ +namespace cltools { -//+PLUMEDOC TOOLS kt +//+PLUMEDOC TOOLS kt /* Print out the value of \f$k_BT\f$ at a particular temperature \par Examples -The following command will tell you the value of \f$k_BT\f$ when T is equal +The following command will tell you the value of \f$k_BT\f$ when T is equal to 300 K in eV \verbatim @@ -52,39 +52,39 @@ plumed kt --temp 300 --units eV //+ENDPLUMEDOC class kt: -public CLTool + public CLTool { public: static void registerKeywords( Keywords& keys ); explicit kt(const CLToolOptions& co ); int main(FILE* in, FILE*out,Communicator& pc); - string description()const{ + string description()const { return "print out the value of kT at a particular temperature"; } }; PLUMED_REGISTER_CLTOOL(kt,"kt") -void kt::registerKeywords( Keywords& keys ){ +void kt::registerKeywords( Keywords& keys ) { CLTool::registerKeywords( keys ); keys.add("compulsory","--temp","print the manual for this particular action"); keys.add("compulsory","--units","kj/mol","the units of energy can be kj/mol, kcal/mol, j/mol, eV or the conversion factor from kj/mol"); } kt::kt(const CLToolOptions& co ): -CLTool(co) + CLTool(co) { inputdata=commandline; } -int kt::main(FILE* in, FILE*out,Communicator& pc){ +int kt::main(FILE* in, FILE*out,Communicator& pc) { - std::string unitname; parse("--units",unitname); - Units units; units.setEnergy( unitname ); - double temp; parse("--temp",temp); - double kk=(kBoltzmann*temp)/units.getEnergy(); - std::fprintf(out,"When the temperature is %f kelvin kT is equal to %f %s\n",temp,kk,unitname.c_str()); - return 0; + std::string unitname; parse("--units",unitname); + Units units; units.setEnergy( unitname ); + double temp; parse("--temp",temp); + double kk=(kBoltzmann*temp)/units.getEnergy(); + std::fprintf(out,"When the temperature is %f kelvin kT is equal to %f %s\n",temp,kk,unitname.c_str()); + return 0; } } // End of namespace diff --git a/src/colvar/Angle.cpp b/src/colvar/Angle.cpp index 4fa0c405c..ed57d03ea 100644 --- a/src/colvar/Angle.cpp +++ b/src/colvar/Angle.cpp @@ -28,8 +28,8 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { //+PLUMEDOC COLVAR ANGLE /* @@ -69,7 +69,7 @@ the angle between vector connecting atom 1 to atom 2 and the vector connecting a on file COLVAR2. \verbatim -a: ANGLE ATOMS=1,2,3 +a: ANGLE ATOMS=1,2,3 # equivalently one could state: # a: ANGLE ATOMS=1,2,2,3 @@ -83,7 +83,7 @@ PRINT ARG=b FILE=COLVAR2 */ //+ENDPLUMEDOC - + class Angle : public Colvar { bool pbc; @@ -96,14 +96,14 @@ public: PLUMED_REGISTER_ACTION(Angle,"ANGLE") -void Angle::registerKeywords( Keywords& keys ){ +void Angle::registerKeywords( Keywords& keys ) { Colvar::registerKeywords(keys); keys.add("atoms","ATOMS","the list of atoms involved in this collective variable (either 3 or 4 atoms)"); } Angle::Angle(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao), -pbc(true) + PLUMED_COLVAR_INIT(ao), + pbc(true) { vector<AtomNumber> atoms; parseAtomList("ATOMS",atoms); @@ -111,14 +111,14 @@ pbc(true) parseFlag("NOPBC",nopbc); pbc=!nopbc; - if(atoms.size()==3){ + if(atoms.size()==3) { log.printf(" between atoms %d %d %d\n",atoms[0].serial(),atoms[1].serial(),atoms[2].serial()); atoms.resize(4); atoms[3]=atoms[2]; atoms[2]=atoms[1]; - }else if(atoms.size()==4){ + } else if(atoms.size()==4) { log.printf(" between lines %d-%d and %d-%d\n",atoms[0].serial(),atoms[1].serial(),atoms[2].serial(),atoms[3].serial()); - }else error("Number of specified atoms should be either 3 or 4"); + } else error("Number of specified atoms should be either 3 or 4"); if(pbc) log.printf(" using periodic boundary conditions\n"); else log.printf(" without periodic boundary conditions\n"); @@ -129,7 +129,7 @@ pbc(true) } // calculator -void Angle::calculate(){ +void Angle::calculate() { if(pbc) makeWhole(); diff --git a/src/colvar/CS2Backbone.cpp b/src/colvar/CS2Backbone.cpp index 617a5d621..040e0dfad 100644 --- a/src/colvar/CS2Backbone.cpp +++ b/src/colvar/CS2Backbone.cpp @@ -25,10 +25,10 @@ #define cutOnDist 0.32 // cut off distance for non-bonded pairwise forces #define cutOffNB2 cutOffNB*cutOffNB // squared buffer distance for neighbour-lists #define cutOffDist2 cutOffDist*cutOffDist -#define cutOnDist2 cutOnDist*cutOnDist +#define cutOnDist2 cutOnDist*cutOnDist #define invswitch 1.0/((cutOffDist2-cutOnDist2)*(cutOffDist2-cutOnDist2)*(cutOffDist2-cutOnDist2)) -#define cutOffDist4 cutOffDist2*cutOffDist2 -#define cutMixed cutOffDist2*cutOffDist2*cutOffDist2 -3.*cutOffDist2*cutOffDist2*cutOnDist2 +#define cutOffDist4 cutOffDist2*cutOffDist2 +#define cutMixed cutOffDist2*cutOffDist2*cutOffDist2 -3.*cutOffDist2*cutOffDist2*cutOnDist2 #include <string> #include <fstream> @@ -46,11 +46,11 @@ using namespace std; namespace PLMD { -namespace colvar{ +namespace colvar { -//+PLUMEDOC COLVAR CS2BACKBONE +//+PLUMEDOC COLVAR CS2BACKBONE /* -This collective variable calculates the backbone chemical shifts for a protein. +This collective variable calculates the backbone chemical shifts for a protein. The functional form is that of CamShift \cite Kohlhoff:2009us. The chemical shifts of the selected nuclei/residues are saved as components. Reference experimental values @@ -63,18 +63,18 @@ shift as in \cite Camilloni:2012je \cite Camilloni:2013hs (see \ref STATS and CamShift calculation is relatively heavy because it often uses a large number of atoms, in order to make it faster it is currently parallelised with \ref Openmp. -As a general rule, when using \ref CS2BACKBONE or other experimental restraints it is better to -increase the accuracy of the constraint algorithm due to the increased strain on the bonded structure. +As a general rule, when using \ref CS2BACKBONE or other experimental restraints it is better to +increase the accuracy of the constraint algorithm due to the increased strain on the bonded structure. In the case of GROMACS it is safer to use lincs-iter=2 and lincs-order=6. In general the system for which chemical shifts are calculated must be completly included in -ATOMS and a TEMPLATE pdb file for the same atoms should be provided as well in the folder DATA. -The atoms are made automatically whole unless NOPBC is used, in particular if the system is made of +ATOMS and a TEMPLATE pdb file for the same atoms should be provided as well in the folder DATA. +The atoms are made automatically whole unless NOPBC is used, in particular if the system is made of by multiple chains it is usually better to use NOPBC and make the molecule whole \ref WHOLEMOLECULES selecting an appropriate order. - + In addition to a pdb file one needs to provide a list of chemical shifts to be calculated using one -file per nucleus type (CAshifts.dat, CBshifts.dat, Cshifts.dat, Hshifts.dat, HAshifts.dat, Nshifts.dat), +file per nucleus type (CAshifts.dat, CBshifts.dat, Cshifts.dat, Hshifts.dat, HAshifts.dat, Nshifts.dat), all the six files should always be present. A chemical shift for a nucleus is calculated if a value greater than 0 is provided. For practical purposes the value can correspond to the experimental value. Residues numbers should go from 1 to N irrespectively of the numbers used in the pdb file. The first and @@ -97,19 +97,19 @@ CAshifts.dat: The default behaviour is to store the values for the active nuclei in components (ca_#, cb_#, co_#, ha_#, hn_#, nh_# and expca_#, expcb_#, expco_#, expha_#, exphn_#, exp_nh#) with NOEXP it is possible to only store the backcalculated values. - -A pdb file is needed to the generate a simple topology of the protein. For histidines in protonation -states different from D the HIE/HSE HIP/HSP name should be used. GLH and ASH can be used for the alternative + +A pdb file is needed to the generate a simple topology of the protein. For histidines in protonation +states different from D the HIE/HSE HIP/HSP name should be used. GLH and ASH can be used for the alternative protonation of GLU and ASP. Non-standard amino acids and other molecules are not yet supported, but in principle -they can be named UNK. If multiple chains are present the chain identifier must be in the standard PDB format, -together with the TER keyword at the end of each chain. +they can be named UNK. If multiple chains are present the chain identifier must be in the standard PDB format, +together with the TER keyword at the end of each chain. One more standard file is also needed in the folder DATA: camshift.db. This file includes all the CamShift parameters -and can be found in regtest/basic/rt45/data/ . +and can be found in regtest/basic/rt45/data/ . -All the above files must be in a single folder that must be specified with the keyword DATA. +All the above files must be in a single folder that must be specified with the keyword DATA. -Additional material and examples can be also found in the tutorial \ref belfast-9 +Additional material and examples can be also found in the tutorial \ref belfast-9 \par Examples @@ -119,15 +119,15 @@ in NMR driven Metadynamics \cite Granata:2013dk : \verbatim whole: GROUP ATOMS=2612-2514:-1,961-1:-1,2466-962:-1,2513-2467:-1 WHOLEMOLECULES ENTITY0=whole -cs: CS2BACKBONE ATOMS=1-2612 NRES=176 DATA=../data/ TEMPLATE=template.pdb CAMSHIFT NOPBC +cs: CS2BACKBONE ATOMS=1-2612 NRES=176 DATA=../data/ TEMPLATE=template.pdb CAMSHIFT NOPBC metad: METAD ARG=cs HEIGHT=0.5 SIGMA=0.1 PACE=200 BIASFACTOR=10 -PRINT ARG=cs,metad.bias FILE=COLVAR STRIDE=100 +PRINT ARG=cs,metad.bias FILE=COLVAR STRIDE=100 \endverbatim -In this second example the chemical shifts are used as replica-averaged restrained as in \cite Camilloni:2012je \cite Camilloni:2013hs. - +In this second example the chemical shifts are used as replica-averaged restrained as in \cite Camilloni:2012je \cite Camilloni:2013hs. + \verbatim -cs: CS2BACKBONE ATOMS=1-174 DATA=data/ NRES=13 +cs: CS2BACKBONE ATOMS=1-174 DATA=data/ NRES=13 encs: ENSEMBLE ARG=(cs\.hn_.*),(cs\.nh_.*) stcs: STATS ARG=encs.* SQDEVSUM PARARG=(cs\.exphn_.*),(cs\.expnh_.*) RESTRAINT ARG=stcs.sqdevsum AT=0 KAPPA=0 SLOPE=24 @@ -166,13 +166,13 @@ class CS2BackboneDB { public: - inline unsigned kind(const string &s){ + inline unsigned kind(const string &s) { if(s=="GLY") return GLY; - else if(s=="PRO") return PRO; + else if(s=="PRO") return PRO; return STD; } - inline unsigned atom_kind(const string &s){ + inline unsigned atom_kind(const string &s) { if(s=="HA")return HA_ATOM; else if(s=="H") return H_ATOM; else if(s=="N") return N_ATOM; @@ -188,17 +188,17 @@ public: inline double * CONSTAACURR(const unsigned a_kind, const unsigned at_kind) {return c_aa[a_kind][at_kind];} inline double * CONSTAANEXT(const unsigned a_kind, const unsigned at_kind) {return c_aa_succ[a_kind][at_kind];} inline double * CONSTAAPREV(const unsigned a_kind, const unsigned at_kind) {return c_aa_prev[a_kind][at_kind];} - inline double * CONST_BB2_PREV(const unsigned a_kind, const unsigned at_kind){return co_bb[a_kind][at_kind];} - inline double * CONST_BB2_CURR(const unsigned a_kind, const unsigned at_kind){return co_bb[a_kind][at_kind]+5;} - inline double * CONST_BB2_NEXT(const unsigned a_kind, const unsigned at_kind){return co_bb[a_kind][at_kind]+11;} - inline double * CONST_SC2(const unsigned a_kind, const unsigned at_kind, unsigned res_type){ return co_sc_[a_kind][at_kind][res_type];} - inline double * CONST_XD(const unsigned a_kind, const unsigned at_kind){ return co_xd[a_kind][at_kind];} - inline double * CO_SPHERE(const unsigned a_kind, const unsigned at_kind, unsigned exp_type){ return co_sphere[a_kind][at_kind][exp_type];} - inline double * CO_RING(const unsigned a_kind, const unsigned at_kind){ return co_ring[a_kind][at_kind];} - inline double * CO_DA(const unsigned a_kind, const unsigned at_kind){ return co_da[a_kind][at_kind];} - inline double * PARS_DA(const unsigned a_kind, const unsigned at_kind, const unsigned ang_kind){ return pars_da[a_kind][at_kind][ang_kind];} - - void parse(const string &file, const double dscale){ + inline double * CONST_BB2_PREV(const unsigned a_kind, const unsigned at_kind) {return co_bb[a_kind][at_kind];} + inline double * CONST_BB2_CURR(const unsigned a_kind, const unsigned at_kind) {return co_bb[a_kind][at_kind]+5;} + inline double * CONST_BB2_NEXT(const unsigned a_kind, const unsigned at_kind) {return co_bb[a_kind][at_kind]+11;} + inline double * CONST_SC2(const unsigned a_kind, const unsigned at_kind, unsigned res_type) { return co_sc_[a_kind][at_kind][res_type];} + inline double * CONST_XD(const unsigned a_kind, const unsigned at_kind) { return co_xd[a_kind][at_kind];} + inline double * CO_SPHERE(const unsigned a_kind, const unsigned at_kind, unsigned exp_type) { return co_sphere[a_kind][at_kind][exp_type];} + inline double * CO_RING(const unsigned a_kind, const unsigned at_kind) { return co_ring[a_kind][at_kind];} + inline double * CO_DA(const unsigned a_kind, const unsigned at_kind) { return co_da[a_kind][at_kind];} + inline double * PARS_DA(const unsigned a_kind, const unsigned at_kind, const unsigned ang_kind) { return pars_da[a_kind][at_kind][ang_kind];} + + void parse(const string &file, const double dscale) { ifstream in; in.open(file.c_str()); if(!in) plumed_merror("Unable to open CS2Backbone DB file " +file); @@ -207,24 +207,24 @@ public: unsigned c_atom = 0; unsigned nline = 0; - for(unsigned i=0;i<3;i++) for(unsigned j=0;j<6;j++) { - for(unsigned k=0;k<20;k++) { - c_aa[i][j][k]=0.; - c_aa_prev[i][j][k]=0.; - c_aa_succ[i][j][k]=0.; - for(unsigned m=0;m<20;m++) co_sc_[i][j][k][m]=0.; - } - for(unsigned k=0;k<16;k++) {co_bb[i][j][k]=0.; } - for(unsigned k=0;k<8;k++) { co_sphere[i][j][0][k]=0.; co_sphere[i][j][1][k]=0.; } - for(unsigned k=0;k<3;k++) { - co_da[i][j][k]=0.; - for(unsigned l=0;l<5;l++) pars_da[i][j][k][l]=0.; + for(unsigned i=0; i<3; i++) for(unsigned j=0; j<6; j++) { + for(unsigned k=0; k<20; k++) { + c_aa[i][j][k]=0.; + c_aa_prev[i][j][k]=0.; + c_aa_succ[i][j][k]=0.; + for(unsigned m=0; m<20; m++) co_sc_[i][j][k][m]=0.; + } + for(unsigned k=0; k<16; k++) {co_bb[i][j][k]=0.; } + for(unsigned k=0; k<8; k++) { co_sphere[i][j][0][k]=0.; co_sphere[i][j][1][k]=0.; } + for(unsigned k=0; k<3; k++) { + co_da[i][j][k]=0.; + for(unsigned l=0; l<5; l++) pars_da[i][j][k][l]=0.; + } + for(unsigned k=0; k<5; k++) co_ring[i][j][k]=0.; + for(unsigned k=0; k<numXtraDists; k++) co_xd[i][j][k]=0.; } - for(unsigned k=0;k<5;k++) co_ring[i][j][k]=0.; - for(unsigned k=0;k<numXtraDists;k++) co_xd[i][j][k]=0.; - } - while(!in.eof()){ + while(!in.eof()) { string line; getline(in,line); ++nline; @@ -232,127 +232,129 @@ public: vector<string> tok; vector<string> tmp; tok = split(line,' '); - for(unsigned q=0;q<tok.size();q++) + for(unsigned q=0; q<tok.size(); q++) if(tok[q].size()) tmp.push_back(tok[q]); tok = tmp; if(tok.size()==0) continue; - if(tok[0]=="PAR"){ + if(tok[0]=="PAR") { c_kind = kind(tok[2]); c_atom = atom_kind(tok[1]); continue; } - else if(tok[0]=="WEIGHT"){ + else if(tok[0]=="WEIGHT") { continue; } - else if(tok[0]=="FLATBTM"){ + else if(tok[0]=="FLATBTM") { continue; } - else if (tok[0] == "SCALEHARM"){ + else if (tok[0] == "SCALEHARM") { continue; } - else if (tok[0] == "TANHAMPLI"){ + else if (tok[0] == "TANHAMPLI") { continue; } - else if (tok[0] == "ENDHARMON"){ + else if (tok[0] == "ENDHARMON") { continue; } - else if (tok[0] == "MAXRCDEVI"){ + else if (tok[0] == "MAXRCDEVI") { continue; } - else if (tok[0] == "RANDCOIL"){ + else if (tok[0] == "RANDCOIL") { continue; } - else if (tok[0] == "CONST"){ + else if (tok[0] == "CONST") { continue; } - else if (tok[0] == "CONSTAA"){ + else if (tok[0] == "CONSTAA") { assign(c_aa[c_kind][c_atom],tok,1); continue; } - else if (tok[0] == "CONSTAA-1"){ + else if (tok[0] == "CONSTAA-1") { assign(c_aa_prev[c_kind][c_atom],tok,1); continue; } - else if (tok[0] == "CONSTAA+1"){ + else if (tok[0] == "CONSTAA+1") { assign(c_aa_succ[c_kind][c_atom],tok,1); continue; } - else if (tok[0] == "COBB1"){ + else if (tok[0] == "COBB1") { continue; } - else if (tok[0] == "COBB2"){ + else if (tok[0] == "COBB2") { //angstrom to nm assign(co_bb[c_kind][c_atom],tok,dscale); continue; } - else if (tok[0] == "SPHERE1"){ + else if (tok[0] == "SPHERE1") { // angstrom^-3 to nm^-3 assign(co_sphere[c_kind][c_atom][0],tok,1./(dscale*dscale*dscale)); continue; } - else if (tok[0] == "SPHERE2"){ + else if (tok[0] == "SPHERE2") { //angstrom to nm assign(co_sphere[c_kind][c_atom][1],tok,dscale); continue; } - else if (tok[0] == "DIHEDRALS"){ + else if (tok[0] == "DIHEDRALS") { assign(co_da[c_kind][c_atom],tok,1); continue; } - else if (tok[0] == "RINGS"){ + else if (tok[0] == "RINGS") { // angstrom^-3 to nm^-3 assign(co_ring[c_kind][c_atom],tok,1./(dscale*dscale*dscale)); - for(unsigned i=1;i<tok.size();i++) + for(unsigned i=1; i<tok.size(); i++) co_ring[c_kind][c_atom][i-1] *= 1000; continue; } - else if (tok[0] == "HBONDS"){ + else if (tok[0] == "HBONDS") { continue; } - else if (tok[0] == "XTRADISTS"){ + else if (tok[0] == "XTRADISTS") { //angstrom to nm assign(co_xd[c_kind][c_atom],tok,dscale); continue; } - else if(tok[0]=="DIHEDPHI"){ + else if(tok[0]=="DIHEDPHI") { assign(pars_da[c_kind][c_atom][0],tok,1); continue; } - else if(tok[0]=="DIHEDPSI"){ + else if(tok[0]=="DIHEDPSI") { assign(pars_da[c_kind][c_atom][1],tok,1); continue; } - else if(tok[0]=="DIHEDCHI1"){ + else if(tok[0]=="DIHEDCHI1") { assign(pars_da[c_kind][c_atom][2],tok,1); continue; } bool ok = false; - string scIdent1 [] = {"COSCALA1", "COSCARG1", "COSCASN1", "COSCASP1", "COSCCYS1", "COSCGLN1", "COSCGLU1", - "COSCGLY1", "COSCHIS1", "COSCILE1", "COSCLEU1", "COSCLYS1", "COSCMET1", "COSCPHE1", - "COSCPRO1", "COSCSER1", "COSCTHR1", "COSCTRP1", "COSCTYR1", "COSCVAL1"}; - - for(unsigned scC = 0; scC < 20; scC++){ - if(tok[0]==scIdent1[scC]){ - ok = true; + string scIdent1 [] = {"COSCALA1", "COSCARG1", "COSCASN1", "COSCASP1", "COSCCYS1", "COSCGLN1", "COSCGLU1", + "COSCGLY1", "COSCHIS1", "COSCILE1", "COSCLEU1", "COSCLYS1", "COSCMET1", "COSCPHE1", + "COSCPRO1", "COSCSER1", "COSCTHR1", "COSCTRP1", "COSCTYR1", "COSCVAL1" + }; + + for(unsigned scC = 0; scC < 20; scC++) { + if(tok[0]==scIdent1[scC]) { + ok = true; break; } } if(ok) continue; - string scIdent2 [] = {"COSCALA2", "COSCARG2", "COSCASN2", "COSCASP2", "COSCCYS2", "COSCGLN2", "COSCGLU2", - "COSCGLY2", "COSCHIS2", "COSCILE2", "COSCLEU2", "COSCLYS2", "COSCMET2", "COSCPHE2", - "COSCPRO2", "COSCSER2", "COSCTHR2", "COSCTRP2", "COSCTYR2", "COSCVAL2"}; + string scIdent2 [] = {"COSCALA2", "COSCARG2", "COSCASN2", "COSCASP2", "COSCCYS2", "COSCGLN2", "COSCGLU2", + "COSCGLY2", "COSCHIS2", "COSCILE2", "COSCLEU2", "COSCLYS2", "COSCMET2", "COSCPHE2", + "COSCPRO2", "COSCSER2", "COSCTHR2", "COSCTRP2", "COSCTYR2", "COSCVAL2" + }; - for(unsigned scC = 0; scC < 20; scC++){ - if(tok[0]==scIdent2[scC]){ + for(unsigned scC = 0; scC < 20; scC++) { + if(tok[0]==scIdent2[scC]) { //angstrom to nm assign(co_sc_[c_kind][c_atom][scC],tok,dscale); ok = true; break; } } if(ok) continue; - + if(tok.size()) { string str_err = "CS2Backbone DB WARNING: unrecognized token: " + tok[0]; plumed_merror(str_err); @@ -377,9 +379,9 @@ private: split(s, delim, elems); return elems; } - - void assign(double * f, const vector<string> & v, const double scale){ - for(unsigned i=1;i<v.size();i++) + + void assign(double * f, const vector<string> & v, const double scale) { + for(unsigned i=1; i<v.size(); i++) f[i-1] = scale*(atof(v[i].c_str())); } }; @@ -410,34 +412,34 @@ class CS2Backbone : public Colvar { double t_chi1; vector<Vector> dd0, dd10, dd21, dd2; - Fragment() { + Fragment() { comp.resize(6); exp_cs.resize(6,0); res_type_prev = res_type_curr = res_type_next = 0; res_kind = 0; fd = 0; - res_name = ""; + res_name = ""; pos.resize(6,-1); prev.reserve(5); curr.reserve(6); next.reserve(5); side_chain.reserve(20); - xd1.reserve(27); - xd2.reserve(27); + xd1.reserve(27); + xd2.reserve(27); box_nb.reserve(250); phi.reserve(4); psi.reserve(4); chi1.reserve(4); t_phi = t_psi = t_chi1 = 0; - dd0.resize(3); - dd10.resize(3); - dd21.resize(3); - dd2.resize(3); + dd0.resize(3); + dd10.resize(3); + dd21.resize(3); + dd2.resize(3); } }; - struct RingInfo{ + struct RingInfo { enum {R_PHE, R_TYR, R_TRP1, R_TRP2, R_HIS}; unsigned rtype; // one out of five different types unsigned atom[6]; // up to six member per ring @@ -451,7 +453,7 @@ class CS2Backbone : public Colvar { RingInfo(): rtype(0),numAtoms(0), lengthN2(NAN),lengthNV(NAN) - {for(unsigned i=0;i<6;i++) atom[i]=0;} + {for(unsigned i=0; i<6; i++) atom[i]=0;} }; enum aa_t {ALA, ARG, ASN, ASP, CYS, GLN, GLU, GLY, HIS, ILE, LEU, LYS, MET, PHE, PRO, SER, THR, TRP, TYR, VAL, UNK}; @@ -496,7 +498,7 @@ public: PLUMED_REGISTER_ACTION(CS2Backbone,"CS2BACKBONE") -void CS2Backbone::registerKeywords( Keywords& keys ){ +void CS2Backbone::registerKeywords( Keywords& keys ) { Colvar::registerKeywords( keys ); componentsAreNotOptional(keys); useCustomisableComponents(keys); @@ -505,26 +507,26 @@ void CS2Backbone::registerKeywords( Keywords& keys ){ keys.add("compulsory","TEMPLATE","template.pdb","A PDB file of the protein system to initialise ALMOST."); keys.add("compulsory","NEIGH_FREQ","20","Period in step for neighbour list update."); keys.add("compulsory","NRES","Number of residues, corresponding to the number of chemical shifts."); - keys.addFlag("CAMSHIFT",false,"Set to TRUE if you to calculate a single CamShift score."); - keys.addFlag("NOEXP",false,"Set to TRUE if you don't want to have fixed components with the experimetnal values."); - keys.addOutputComponent("ha","default","the calculated Ha hydrogen chemical shifts"); - keys.addOutputComponent("hn","default","the calculated H hydrogen chemical shifts"); - keys.addOutputComponent("nh","default","the calculated N nitrogen chemical shifts"); - keys.addOutputComponent("ca","default","the calculated Ca carbon chemical shifts"); - keys.addOutputComponent("cb","default","the calculated Cb carbon chemical shifts"); - keys.addOutputComponent("co","default","the calculated C' carbon chemical shifts"); - keys.addOutputComponent("expha","default","the experimental Ha hydrogen chemical shifts"); - keys.addOutputComponent("exphn","default","the experimental H hydrogen chemical shifts"); - keys.addOutputComponent("expnh","default","the experimental N nitrogen chemical shifts"); - keys.addOutputComponent("expca","default","the experimental Ca carbon chemical shifts"); - keys.addOutputComponent("expcb","default","the experimental Cb carbon chemical shifts"); - keys.addOutputComponent("expco","default","the experimental C' carbon chemical shifts"); + keys.addFlag("CAMSHIFT",false,"Set to TRUE if you to calculate a single CamShift score."); + keys.addFlag("NOEXP",false,"Set to TRUE if you don't want to have fixed components with the experimetnal values."); + keys.addOutputComponent("ha","default","the calculated Ha hydrogen chemical shifts"); + keys.addOutputComponent("hn","default","the calculated H hydrogen chemical shifts"); + keys.addOutputComponent("nh","default","the calculated N nitrogen chemical shifts"); + keys.addOutputComponent("ca","default","the calculated Ca carbon chemical shifts"); + keys.addOutputComponent("cb","default","the calculated Cb carbon chemical shifts"); + keys.addOutputComponent("co","default","the calculated C' carbon chemical shifts"); + keys.addOutputComponent("expha","default","the experimental Ha hydrogen chemical shifts"); + keys.addOutputComponent("exphn","default","the experimental H hydrogen chemical shifts"); + keys.addOutputComponent("expnh","default","the experimental N nitrogen chemical shifts"); + keys.addOutputComponent("expca","default","the experimental Ca carbon chemical shifts"); + keys.addOutputComponent("expcb","default","the experimental Cb carbon chemical shifts"); + keys.addOutputComponent("expco","default","the experimental C' carbon chemical shifts"); } CS2Backbone::CS2Backbone(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao), -camshift(false), -pbc(true) + PLUMED_COLVAR_INIT(ao), + camshift(false), + pbc(true) { string stringadb; string stringapdb; @@ -561,7 +563,7 @@ pbc(true) } log.printf(" Initialization of the predictor ...\n"); log.flush(); - db.parse(stringadb,scale); + db.parse(stringadb,scale); PDB pdb; if( !pdb.read(stringapdb,plumed.getAtoms().usingNaturalUnits(),1./scale) ) error("missing input file " + stringapdb); init_backbone(pdb); @@ -595,18 +597,18 @@ pbc(true) /* this is a workaround for those chemical shifts that can result in too large forces */ remove_problematic("GLN", "CB"); remove_problematic("ILE", "CB"); - remove_problematic("PRO", "N"); + remove_problematic("PRO", "N"); remove_problematic("PRO", "H"); remove_problematic("PRO", "CB"); remove_problematic("GLY", "HA"); remove_problematic("GLY", "CB"); /* this is a workaround for those chemical shifts that are not parameterized */ remove_problematic("HIE", "HA"); remove_problematic("HIP", "HA"); remove_problematic("HSP", "HA"); - remove_problematic("HIE", "H"); remove_problematic("HIP", "H"); remove_problematic("HSP", "H"); - remove_problematic("HIE", "N"); remove_problematic("HIP", "N"); remove_problematic("HSP", "N"); + remove_problematic("HIE", "H"); remove_problematic("HIP", "H"); remove_problematic("HSP", "H"); + remove_problematic("HIE", "N"); remove_problematic("HIP", "N"); remove_problematic("HSP", "N"); remove_problematic("HIE", "CA"); remove_problematic("HIP", "CA"); remove_problematic("HSP", "CA"); remove_problematic("HIE", "CB"); remove_problematic("HIP", "CB"); remove_problematic("HSP", "CB"); - remove_problematic("HIE", "C"); remove_problematic("HIP", "C"); remove_problematic("HSP", "C"); + remove_problematic("HIE", "C"); remove_problematic("HIP", "C"); remove_problematic("HSP", "C"); remove_problematic("GLH", "HA"); remove_problematic("ASH", "HA"); remove_problematic("HSE", "HA"); remove_problematic("GLH", "H"); remove_problematic("ASH", "H"); remove_problematic("HSE", "H"); remove_problematic("GLH", "N"); remove_problematic("ASH", "N"); remove_problematic("HSE", "N"); @@ -646,11 +648,11 @@ pbc(true) unsigned index=0; if(camshift) noexp = true; if(!camshift) { - for(unsigned i=0;i<atom.size();i++) { - for(unsigned a=0;a<atom[i].size();a++) { + for(unsigned i=0; i<atom.size(); i++) { + for(unsigned a=0; a<atom[i].size(); a++) { unsigned res=index+a; std::string num; Tools::convert(res,num); - for(unsigned at_kind=0;at_kind<6;at_kind++){ + for(unsigned at_kind=0; at_kind<6; at_kind++) { if(atom[i][a].exp_cs[at_kind]!=0) { addComponentWithDerivatives(str_cs[at_kind]+num); componentIsNotPeriodic(str_cs[at_kind]+num); @@ -663,20 +665,20 @@ pbc(true) } else { addValueWithDerivatives(); setNotPeriodic(); - for(unsigned i=0;i<atom.size();i++) { + for(unsigned i=0; i<atom.size(); i++) { index += atom[i].size(); } } if(!noexp) { - index = 0; - for(unsigned i=0;i<atom.size();i++) { - for(unsigned a=0;a<atom[i].size();a++) { + index = 0; + for(unsigned i=0; i<atom.size(); i++) { + for(unsigned a=0; a<atom[i].size(); a++) { unsigned res=index+a; std::string num; Tools::convert(res,num); - for(unsigned at_kind=0;at_kind<6;at_kind++){ + for(unsigned at_kind=0; at_kind<6; at_kind++) { if(atom[i][a].exp_cs[at_kind]!=0) { - addComponent("exp"+str_cs[at_kind]+num); + addComponent("exp"+str_cs[at_kind]+num); componentIsNotPeriodic("exp"+str_cs[at_kind]+num); Value* comp=getPntrToComponent("exp"+str_cs[at_kind]+num); comp->set(atom[i][a].exp_cs[at_kind]); @@ -689,7 +691,7 @@ pbc(true) /* temporary check, the idea is that I can remove NRES completely */ if(index!=numResidues) error("NRES and the number of residues in the PDB do not match!"); - + requestAtoms(atoms); } @@ -703,8 +705,8 @@ void CS2Backbone::remove_problematic(const string &res, const string &nucl) { else if(nucl=="C") n=5; else return; - for(unsigned i=0;i<atom.size();i++){ - for(unsigned a=0;a<atom[i].size();a++){ + for(unsigned i=0; i<atom.size(); i++) { + for(unsigned a=0; a<atom[i].size(); a++) { if(atom[i][a].res_name.c_str()==res) { atom[i][a].exp_cs[n] = 0; } @@ -712,7 +714,7 @@ void CS2Backbone::remove_problematic(const string &res, const string &nucl) { } } -void CS2Backbone::read_cs(const string &file, const string &nucl){ +void CS2Backbone::read_cs(const string &file, const string &nucl) { ifstream in; in.open(file.c_str()); if(!in) error("CS2Backbone: Unable to open " + file); @@ -729,10 +731,10 @@ void CS2Backbone::read_cs(const string &file, const string &nucl){ int oldseg = -1; int oldp = -1; - while(iter!=end){ + while(iter!=end) { string tok; tok = *iter; ++iter; - if(tok[0]=='#'){ ++iter; continue;} + if(tok[0]=='#') { ++iter; continue;} unsigned p = atoi(tok.c_str()); p = p - 1; const unsigned seg = frag_segment(p); @@ -765,7 +767,7 @@ void CS2Backbone::calculate() double score = 0.; vector<double> camshift_sigma2(6); - camshift_sigma2[0] = 0.08; // HA + camshift_sigma2[0] = 0.08; // HA camshift_sigma2[1] = 0.30; // HN camshift_sigma2[2] = 9.00; // NH camshift_sigma2[3] = 1.30; // CA @@ -777,13 +779,13 @@ void CS2Backbone::calculate() // CYCLE OVER MULTIPLE CHAINS #pragma omp parallel num_threads(OpenMP::getNumThreads()) - for(unsigned s=0;s<chainsize;s++){ + for(unsigned s=0; s<chainsize; s++) { const unsigned psize = atom[s].size(); vector<Vector> omp_deriv; if(camshift) omp_deriv.resize(getNumberOfAtoms(), Vector(0,0,0)); #pragma omp for reduction(+:score) // SKIP FIRST AND LAST RESIDUE OF EACH CHAIN - for(unsigned a=1;a<psize-1;a++){ + for(unsigned a=1; a<psize-1; a++) { const Fragment *myfrag = &atom[s][a]; const unsigned aa_kind = myfrag->res_kind; @@ -796,7 +798,7 @@ void CS2Backbone::calculate() const unsigned xdsize=myfrag->xd1.size(); vector<Vector> ext_distances(xdsize); vector<double> ext_d(xdsize); - for(unsigned q=0;q<xdsize;q++){ + for(unsigned q=0; q<xdsize; q++) { if(myfrag->xd1[q]==-1||myfrag->xd2[q]==-1) continue; const Vector distance = delta(getPosition(myfrag->xd1[q]),getPosition(myfrag->xd2[q])); ext_d[q] = distance.modulo(); @@ -804,30 +806,30 @@ void CS2Backbone::calculate() } // CYCLE OVER THE SIX BACKBONE CHEMICAL SHIFTS - for(unsigned at_kind=0;at_kind<6;at_kind++){ - if(atom[s][a].exp_cs[at_kind]!=0){ + for(unsigned at_kind=0; at_kind<6; at_kind++) { + if(atom[s][a].exp_cs[at_kind]!=0) { // Common constant and AATYPE const double * CONSTAACURR = db.CONSTAACURR(aa_kind,at_kind); const double * CONSTAANEXT = db.CONSTAANEXT(aa_kind,at_kind); const double * CONSTAAPREV = db.CONSTAAPREV(aa_kind,at_kind); - double cs = CONSTAACURR[res_type_curr] + - CONSTAANEXT[res_type_next] + + double cs = CONSTAACURR[res_type_curr] + + CONSTAANEXT[res_type_next] + CONSTAAPREV[res_type_prev]; - // this is the atom for which we are calculating the chemical shift + // this is the atom for which we are calculating the chemical shift const unsigned ipos = myfrag->pos[at_kind]; vector<unsigned> list; list.reserve(needed_atoms); list.push_back(ipos); vector<Vector> ff; - ff.reserve(needed_atoms); + ff.reserve(needed_atoms); ff.push_back(Vector(0,0,0)); //PREV const double * CONST_BB2_PREV = db.CONST_BB2_PREV(aa_kind,at_kind); const unsigned presize = myfrag->prev.size(); - for(unsigned q=0;q<presize;q++){ + for(unsigned q=0; q<presize; q++) { const double cb2pq = CONST_BB2_PREV[q]; if(cb2pq==0.) continue; const unsigned jpos = myfrag->prev[q]; @@ -845,7 +847,7 @@ void CS2Backbone::calculate() //CURR const double * CONST_BB2_CURR = db.CONST_BB2_CURR(aa_kind,at_kind); const unsigned cursize = myfrag->curr.size(); - for(unsigned q=0;q<cursize;q++){ + for(unsigned q=0; q<cursize; q++) { const double cb2cq = CONST_BB2_CURR[q]; if(cb2cq==0.) continue; const unsigned jpos = myfrag->curr[q]; @@ -864,8 +866,8 @@ void CS2Backbone::calculate() //NEXT const double * CONST_BB2_NEXT = db.CONST_BB2_NEXT(aa_kind,at_kind); const unsigned nexsize = myfrag->next.size(); - for(unsigned q=0;q<nexsize;q++){ - const double cb2nq = CONST_BB2_NEXT[q]; + for(unsigned q=0; q<nexsize; q++) { + const double cb2nq = CONST_BB2_NEXT[q]; if(cb2nq==0.) continue; const unsigned jpos = myfrag->next[q]; list.push_back(jpos); @@ -882,8 +884,8 @@ void CS2Backbone::calculate() //SIDE CHAIN const double * CONST_SC2 = db.CONST_SC2(aa_kind,at_kind,res_type_curr); const unsigned sidsize = myfrag->side_chain.size(); - for(unsigned q=0;q<sidsize;q++){ - const double cs2q = CONST_SC2[q]; + for(unsigned q=0; q<sidsize; q++) { + const double cs2q = CONST_SC2[q]; if(cs2q==0.) continue; const unsigned jpos = myfrag->side_chain[q]; if(ipos==jpos) continue; @@ -897,10 +899,10 @@ void CS2Backbone::calculate() ff[0] += der; ff.push_back(-der); } - + //EXTRA DIST const double * CONST_XD = db.CONST_XD(aa_kind,at_kind); - for(unsigned q=0;q<xdsize;q++){ + for(unsigned q=0; q<xdsize; q++) { const double cxdq = CONST_XD[q]; if(cxdq==0.) continue; if(myfrag->xd1[q]==-1||myfrag->xd2[q]==-1) continue; @@ -911,7 +913,7 @@ void CS2Backbone::calculate() ff.push_back( der); ff.push_back(-der); } - + //NON BOND { const double * CONST_CO_SPHERE3 = db.CO_SPHERE(aa_kind,at_kind,0); @@ -921,22 +923,22 @@ void CS2Backbone::calculate() const unsigned jpos = myfrag->box_nb[bat]; const Vector distance = delta(getPosition(jpos),getPosition(ipos)); const double d2 = distance.modulo2(); - + if(d2<cutOffDist2) { double factor1 = sqrt(d2); double dfactor1 = 1./factor1; - double factor3 = dfactor1*dfactor1*dfactor1; + double factor3 = dfactor1*dfactor1*dfactor1; double dfactor3 = -3.*factor3*dfactor1*dfactor1; if(d2>cutOnDist2) { const double af = cutOffDist2 - d2; const double bf = cutOffDist2 - 3.*cutOnDist2 + 2.*d2; - const double cf = invswitch*af; + const double cf = invswitch*af; const double df = cf*af*bf; - factor1 *= df; + factor1 *= df; factor3 *= df; - const double d4 = d2*d2; + const double d4 = d2*d2; const double af1 = 15.*cutOnDist2*d2; const double bf1 = -14.*d4; const double cf1 = -3.*cutOffDist2*cutOnDist2 + cutOffDist2*d2; @@ -950,14 +952,14 @@ void CS2Backbone::calculate() dfactor3 *= invswitch*(cutMixed+df3); } - const unsigned t = type[jpos]; + const unsigned t = type[jpos]; cs += factor1*CONST_CO_SPHERE[t] + factor3*CONST_CO_SPHERE3[t] ; - const double fact = dfactor1*CONST_CO_SPHERE[t]+dfactor3*CONST_CO_SPHERE3[t]; + const double fact = dfactor1*CONST_CO_SPHERE[t]+dfactor3*CONST_CO_SPHERE3[t]; const Vector der = fact*distance; list.push_back(jpos); ff[0] += der; - ff.push_back(-der); + ff.push_back(-der); } } } @@ -967,64 +969,64 @@ void CS2Backbone::calculate() { const double *rc = db.CO_RING(aa_kind,at_kind); const unsigned rsize = ringInfo.size(); - for(unsigned i=0; i<rsize; i++){ - // compute angle from ring middle point to current atom position - // get distance vector from query atom to ring center and normal vector to ring plane - const Vector n = ringInfo[i].normVect; - const double nL = ringInfo[i].lengthNV; - const double inL2 = ringInfo[i].lengthN2; + for(unsigned i=0; i<rsize; i++) { + // compute angle from ring middle point to current atom position + // get distance vector from query atom to ring center and normal vector to ring plane + const Vector n = ringInfo[i].normVect; + const double nL = ringInfo[i].lengthNV; + const double inL2 = ringInfo[i].lengthN2; const Vector d = delta(ringInfo[i].position, getPosition(ipos)); - const double dL2 = d.modulo2(); - const double dL = sqrt(dL2); - const double idL3 = 1./(dL2*dL); + const double dL2 = d.modulo2(); + const double dL = sqrt(dL2); + const double idL3 = 1./(dL2*dL); - const double dn = dotProduct(d,n); - const double dn2 = dn*dn; - const double dLnL = dL*nL; + const double dn = dotProduct(d,n); + const double dn2 = dn*dn; + const double dLnL = dL*nL; const double dL_nL = dL/nL; - const double ang2 = dn2*inL2/dL2; - const double u = 1.-3.*ang2; + const double ang2 = dn2*inL2/dL2; + const double u = 1.-3.*ang2; const double cc = rc[ringInfo[i].rtype]; cs += cc*u*idL3; - - const double fUU = -6*dn*inL2; - const double fUQ = fUU/dL; + + const double fUU = -6*dn*inL2; + const double fUQ = fUU/dL; const Vector gradUQ = fUQ*(dL2*n - dn*d); const Vector gradVQ = (3*dL*u)*d; - - const double fact = cc*idL3*idL3; - ff[0] += fact*(gradUQ - gradVQ); - - const double fU = fUU/nL; - double OneOverN = 1./6.; - if(ringInfo[i].numAtoms==5) OneOverN=1./3.; + + const double fact = cc*idL3*idL3; + ff[0] += fact*(gradUQ - gradVQ); + + const double fU = fUU/nL; + double OneOverN = 1./6.; + if(ringInfo[i].numAtoms==5) OneOverN=1./3.; const Vector factor2 = OneOverN*n; - const Vector factor4 = (OneOverN/dL_nL)*d; + const Vector factor4 = (OneOverN/dL_nL)*d; const Vector gradV = -OneOverN*gradVQ; if(ringInfo[i].numAtoms==6) { - // update forces on ring atoms - for(unsigned at=0;at<6;at++) { + // update forces on ring atoms + for(unsigned at=0; at<6; at++) { const Vector ab = crossProduct(d,ringInfo[i].g[at]); const Vector c = crossProduct(n,ringInfo[i].g[at]); - const Vector factor3 = 0.5*dL_nL*c; + const Vector factor3 = 0.5*dL_nL*c; const Vector factor1 = 0.5*ab; const Vector gradU = fU*( dLnL*(factor1 - factor2) -dn*(factor3 - factor4) ); - ff.push_back(fact*(gradU - gradV)); + ff.push_back(fact*(gradU - gradV)); list.push_back(ringInfo[i].atom[at]); } } else { - for(unsigned at=0;at<3;at++) { + for(unsigned at=0; at<3; at++) { const Vector ab = crossProduct(d,ringInfo[i].g[at]); const Vector c = crossProduct(n,ringInfo[i].g[at]); - const Vector factor3 = dL_nL*c; + const Vector factor3 = dL_nL*c; const Vector factor1 = ab; const Vector gradU = fU*( dLnL*(factor1 - factor2) -dn*(factor3 - factor4) ); - ff.push_back(fact*(gradU - gradV)); + ff.push_back(fact*(gradU - gradV)); } list.push_back(ringInfo[i].atom[0]); list.push_back(ringInfo[i].atom[2]); @@ -1037,11 +1039,11 @@ void CS2Backbone::calculate() //DIHEDRAL ANGLES { const double *CO_DA = db.CO_DA(aa_kind,at_kind); - if(myfrag->phi.size()==4){ - const double *PARS_DA = db.PARS_DA(aa_kind,at_kind,0); + if(myfrag->phi.size()==4) { + const double *PARS_DA = db.PARS_DA(aa_kind,at_kind,0); const double val1 = 3.*myfrag->t_phi+PARS_DA[3]; const double val2 = myfrag->t_phi+PARS_DA[4]; - cs += CO_DA[0]*(PARS_DA[0]*cos(val1)+PARS_DA[1]*cos(val2)+PARS_DA[2]); + cs += CO_DA[0]*(PARS_DA[0]*cos(val1)+PARS_DA[1]*cos(val2)+PARS_DA[2]); const double fact = -CO_DA[0]*(+3.*PARS_DA[0]*sin(val1)+PARS_DA[1]*sin(val2)); ff.push_back(fact*myfrag->dd0[0]); @@ -1054,11 +1056,11 @@ void CS2Backbone::calculate() list.push_back(myfrag->phi[3]); } - if(myfrag->psi.size()==4){ - const double *PARS_DA = db.PARS_DA(aa_kind,at_kind,1); + if(myfrag->psi.size()==4) { + const double *PARS_DA = db.PARS_DA(aa_kind,at_kind,1); const double val1 = 3.*myfrag->t_psi+PARS_DA[3]; const double val2 = myfrag->t_psi+PARS_DA[4]; - cs += CO_DA[1]*(PARS_DA[0]*cos(val1)+PARS_DA[1]*cos(val2)+PARS_DA[2]); + cs += CO_DA[1]*(PARS_DA[0]*cos(val1)+PARS_DA[1]*cos(val2)+PARS_DA[2]); const double fact = -CO_DA[1]*(+3.*PARS_DA[0]*sin(val1)+PARS_DA[1]*sin(val2)); ff.push_back(fact*myfrag->dd0[1]); @@ -1072,11 +1074,11 @@ void CS2Backbone::calculate() } //Chi - if(myfrag->chi1.size()==4){ - const double *PARS_DA = db.PARS_DA(aa_kind,at_kind,2); + if(myfrag->chi1.size()==4) { + const double *PARS_DA = db.PARS_DA(aa_kind,at_kind,2); const double val1 = 3.*myfrag->t_chi1+PARS_DA[3]; const double val2 = myfrag->t_chi1+PARS_DA[4]; - cs += CO_DA[2]*(PARS_DA[0]*cos(val1)+PARS_DA[1]*cos(val2)+PARS_DA[2]); + cs += CO_DA[2]*(PARS_DA[0]*cos(val1)+PARS_DA[1]*cos(val2)+PARS_DA[2]); const double fact = -CO_DA[2]*(+3.*PARS_DA[0]*sin(val1)+PARS_DA[1]*sin(val2)); ff.push_back(fact*myfrag->dd0[2]); @@ -1093,13 +1095,13 @@ void CS2Backbone::calculate() Value * comp; double fact = 1.0; - if(!camshift) { + if(!camshift) { comp = atom[s][a].comp[at_kind]; comp->set(cs); Tensor virial; - for(unsigned i=0;i<list.size();i++) { - setAtomsDerivatives(comp,list[i],fact*ff[i]); - virial-=Tensor(getPosition(list[i]),fact*ff[i]); + for(unsigned i=0; i<list.size(); i++) { + setAtomsDerivatives(comp,list[i],fact*ff[i]); + virial-=Tensor(getPosition(list[i]),fact*ff[i]); } setBoxDerivatives(comp,virial); } else { @@ -1107,13 +1109,13 @@ void CS2Backbone::calculate() comp = getPntrToValue(); score += (cs - atom[s][a].exp_cs[at_kind])*(cs - atom[s][a].exp_cs[at_kind])/camshift_sigma2[at_kind]; fact = 2.0*(cs - atom[s][a].exp_cs[at_kind])/camshift_sigma2[at_kind]; - for(unsigned i=0;i<list.size();i++) omp_deriv[list[i]] += fact*ff[i]; + for(unsigned i=0; i<list.size(); i++) omp_deriv[list[i]] += fact*ff[i]; } - } + } } } #pragma omp critical - if(camshift) for(int i=0;i<getPositions().size();i++) setAtomsDerivatives(i,omp_deriv[i]); + if(camshift) for(int i=0; i<getPositions().size(); i++) setAtomsDerivatives(i,omp_deriv[i]); } // in the case of camshift we calculate the virial at the end @@ -1126,12 +1128,12 @@ void CS2Backbone::calculate() if(box_count == box_nupdate) box_count = 0; } -void CS2Backbone::update_neighb(){ +void CS2Backbone::update_neighb() { const unsigned chainsize = atom.size(); - for(unsigned s=0;s<chainsize;s++){ + for(unsigned s=0; s<chainsize; s++) { const unsigned psize = atom[s].size(); #pragma omp parallel for num_threads(OpenMP::getNumThreads()) - for(unsigned a=1;a<psize-1;a++){ + for(unsigned a=1; a<psize-1; a++) { const unsigned boxsize = getNumberOfAtoms(); atom[s][a].box_nb.clear(); atom[s][a].box_nb.reserve(300); @@ -1139,14 +1141,14 @@ void CS2Backbone::update_neighb(){ for(unsigned bat=0; bat<boxsize; bat++) { const unsigned res_dist = abs(static_cast<int>(res_curr-res_num[bat])); if(res_dist<2) continue; - for(unsigned at_kind=0;at_kind<6; at_kind++) { + for(unsigned at_kind=0; at_kind<6; at_kind++) { if(atom[s][a].exp_cs[at_kind]==0.) continue; - const unsigned ipos = atom[s][a].pos[at_kind]; + const unsigned ipos = atom[s][a].pos[at_kind]; const Vector distance = delta(getPosition(bat),getPosition(ipos)); const double d2=distance.modulo2(); - if(d2<cutOffNB2) { - atom[s][a].box_nb.push_back(bat); - break; + if(d2<cutOffNB2) { + atom[s][a].box_nb.push_back(bat); + break; } } } @@ -1154,8 +1156,8 @@ void CS2Backbone::update_neighb(){ } } -void CS2Backbone::compute_ring_parameters(){ - for(unsigned i=0;i<ringInfo.size();i++){ +void CS2Backbone::compute_ring_parameters() { + for(unsigned i=0; i<ringInfo.size(); i++) { const unsigned size = ringInfo[i].numAtoms; if(size==6) { ringInfo[i].g[0] = delta(getPosition(ringInfo[i].atom[4]),getPosition(ringInfo[i].atom[2])); @@ -1199,19 +1201,19 @@ void CS2Backbone::compute_ring_parameters(){ } // calculate squared length and length of normal vector - ringInfo[i].lengthN2 = 1./ringInfo[i].normVect.modulo2(); + ringInfo[i].lengthN2 = 1./ringInfo[i].normVect.modulo2(); ringInfo[i].lengthNV = 1./sqrt(ringInfo[i].lengthN2); } } -void CS2Backbone::compute_dihedrals(){ +void CS2Backbone::compute_dihedrals() { const unsigned chainsize = atom.size(); - for(unsigned s=0;s<chainsize;s++){ + for(unsigned s=0; s<chainsize; s++) { const unsigned psize = atom[s].size(); - #pragma omp parallel for num_threads(OpenMP::getNumThreads()) - for(unsigned a=1;a<psize-1;a++){ + #pragma omp parallel for num_threads(OpenMP::getNumThreads()) + for(unsigned a=1; a<psize-1; a++) { const Fragment *myfrag = &atom[s][a]; - if(myfrag->phi.size()==4){ + if(myfrag->phi.size()==4) { const Vector d0 = delta(getPosition(myfrag->phi[1]), getPosition(myfrag->phi[0])); const Vector d1 = delta(getPosition(myfrag->phi[2]), getPosition(myfrag->phi[1])); const Vector d2 = delta(getPosition(myfrag->phi[3]), getPosition(myfrag->phi[2])); @@ -1223,7 +1225,7 @@ void CS2Backbone::compute_dihedrals(){ atom[s][a].dd21[0] = dd2-dd1; atom[s][a].dd2[0] = dd2; } - if(myfrag->psi.size()==4){ + if(myfrag->psi.size()==4) { const Vector d0 = delta(getPosition(myfrag->psi[1]), getPosition(myfrag->psi[0])); const Vector d1 = delta(getPosition(myfrag->psi[2]), getPosition(myfrag->psi[1])); const Vector d2 = delta(getPosition(myfrag->psi[3]), getPosition(myfrag->psi[2])); @@ -1235,7 +1237,7 @@ void CS2Backbone::compute_dihedrals(){ atom[s][a].dd21[1] = dd2-dd1; atom[s][a].dd2[1] = dd2; } - if(myfrag->chi1.size()==4){ + if(myfrag->chi1.size()==4) { const Vector d0 = delta(getPosition(myfrag->chi1[1]), getPosition(myfrag->chi1[0])); const Vector d1 = delta(getPosition(myfrag->chi1[2]), getPosition(myfrag->chi1[1])); const Vector d2 = delta(getPosition(myfrag->chi1[3]), getPosition(myfrag->chi1[2])); @@ -1251,14 +1253,14 @@ void CS2Backbone::compute_dihedrals(){ } } -void CS2Backbone::init_backbone(const PDB &pdb){ +void CS2Backbone::init_backbone(const PDB &pdb) { // number of chains vector<string> chains; pdb.getChainNames( chains ); seg_last.resize(chains.size()); unsigned old_size=0; - for(unsigned i=0;i<chains.size();i++){ + for(unsigned i=0; i<chains.size(); i++) { unsigned start, end; string errmsg; pdb.getResidueRange( chains[i], start, end, errmsg ); @@ -1288,7 +1290,7 @@ void CS2Backbone::init_backbone(const PDB &pdb){ vector<AtomNumber> allatoms = pdb.getAtomsInChain(chains[i]); // cycle over all the atoms in the chain - for(unsigned a=0;a<allatoms.size();a++){ + for(unsigned a=0; a<allatoms.size(); a++) { unsigned atm_index=a+old_size; unsigned f = pdb.getResidueNumber(allatoms[a]); unsigned f_idx = f-res_offset; @@ -1308,8 +1310,8 @@ void CS2Backbone::init_backbone(const PDB &pdb){ // vector of residues for a given chain vector<Fragment> atm_; - // cycle over all residues in the chain - for(unsigned a=start;a<=end;a++){ + // cycle over all residues in the chain + for(unsigned a=start; a<=end; a++) { unsigned f_idx = a - res_offset; Fragment at; at.pos[0] = HA_[f_idx]; @@ -1319,17 +1321,17 @@ void CS2Backbone::init_backbone(const PDB &pdb){ at.pos[4] = CB_[f_idx]; at.pos[5] = C_[f_idx]; at.res_type_prev = at.res_type_curr = at.res_type_next = 0; - at.res_name = pdb.getResidueName(a, chains[i]); + at.res_name = pdb.getResidueName(a, chains[i]); at.res_kind = db.kind(at.res_name); at.fd = a; //REGISTER PREV CURR NEXT { - if(a>start){ + if(a>start) { at.prev.push_back( N_[f_idx-1]); at.prev.push_back(CA_[f_idx-1]); at.prev.push_back(HA_[f_idx-1]); at.prev.push_back( C_[f_idx-1]); - at.prev.push_back( O_[f_idx-1]); + at.prev.push_back( O_[f_idx-1]); at.res_type_prev = frag2enum(pdb.getResidueName(a-1, chains[i])); } @@ -1338,10 +1340,10 @@ void CS2Backbone::init_backbone(const PDB &pdb){ at.curr.push_back(CA_[f_idx]); at.curr.push_back(HA_[f_idx]); at.curr.push_back( C_[f_idx]); - at.curr.push_back( O_[f_idx]); + at.curr.push_back( O_[f_idx]); at.res_type_curr = frag2enum(pdb.getResidueName(a, chains[i])); - if(a<end){ + if(a<end) { at.next.push_back (N_[f_idx+1]); at.next.push_back (H_[f_idx+1]); at.next.push_back(CA_[f_idx+1]); @@ -1351,21 +1353,21 @@ void CS2Backbone::init_backbone(const PDB &pdb){ } //PHI | PSI | CH1 - if(a>start){ + if(a>start) { at.phi.push_back( C_[f_idx-1]); at.phi.push_back( N_[f_idx]); at.phi.push_back(CA_[f_idx]); at.phi.push_back( C_[f_idx]); } - - if(a<end){ + + if(a<end) { at.psi.push_back( N_[f_idx]); at.psi.push_back(CA_[f_idx]); at.psi.push_back( C_[f_idx]); - at.psi.push_back( N_[f_idx+1]); + at.psi.push_back( N_[f_idx+1]); } - if(CX_[f_idx]!=-1&&CB_[f_idx]!=-1){ + if(CX_[f_idx]!=-1&&CB_[f_idx]!=-1) { at.chi1.push_back( N_[f_idx]); at.chi1.push_back(CA_[f_idx]); at.chi1.push_back(CB_[f_idx]); @@ -1378,69 +1380,72 @@ void CS2Backbone::init_backbone(const PDB &pdb){ } } -void CS2Backbone::init_sidechain(const PDB &pdb){ - vector<string> chains; +void CS2Backbone::init_sidechain(const PDB &pdb) { + vector<string> chains; pdb.getChainNames( chains ); unsigned old_size=0; // cycle over chains - for(unsigned s=0; s<atom.size(); s++){ - AtomNumber astart, aend; + for(unsigned s=0; s<atom.size(); s++) { + AtomNumber astart, aend; string errmsg; pdb.getAtomRange( chains[s], astart, aend, errmsg ); unsigned atom_offset = astart.index(); - // cycle over residues - for(unsigned a=0; a<atom[s].size(); a++){ + // cycle over residues + for(unsigned a=0; a<atom[s].size(); a++) { if(atom[s][a].res_name=="UNK") continue; vector<AtomNumber> atm = pdb.getAtomsInResidue(atom[s][a].fd, chains[s]); vector<string> sc_atm = side_chain_atoms(atom[s][a].res_name); - for(unsigned sc=0;sc<sc_atm.size();sc++){ - for(unsigned aa=0;aa<atm.size();aa++){ - if(pdb.getAtomName(atm[aa])==sc_atm[sc]){ - atom[s][a].side_chain.push_back(atm[aa].index()-atom_offset+old_size); + for(unsigned sc=0; sc<sc_atm.size(); sc++) { + for(unsigned aa=0; aa<atm.size(); aa++) { + if(pdb.getAtomName(atm[aa])==sc_atm[sc]) { + atom[s][a].side_chain.push_back(atm[aa].index()-atom_offset+old_size); } } } } - old_size += aend.index()+1; + old_size += aend.index()+1; } } -void CS2Backbone::init_xdist(const PDB &pdb){ - const string atomsP1[] = {"H", "H", "H", "C", "C", "C", - "O", "O", "O", "N", "N", "N", - "O", "O", "O", "N", "N", "N", - "CG", "CG", "CG", "CG", "CG", - "CG", "CG", "CA"}; - - const int resOffsetP1 [] = {0, 0, 0, -1, -1, -1, - 0, 0, 0, 1, 1, 1, - -1, -1, -1, 0, 0, 0, - 0, 0, 0, 0, 0, -1, 1, -1}; - - const string atomsP2[] = {"HA", "C", "CB", "HA", "C", "CB", - "HA", "N", "CB", "HA", "N", "CB", - "HA", "N", "CB", "HA", "N", "CB", - "HA", "N", "C", "C", "N", "CA", "CA", "CA"}; +void CS2Backbone::init_xdist(const PDB &pdb) { + const string atomsP1[] = {"H", "H", "H", "C", "C", "C", + "O", "O", "O", "N", "N", "N", + "O", "O", "O", "N", "N", "N", + "CG", "CG", "CG", "CG", "CG", + "CG", "CG", "CA" + }; + + const int resOffsetP1 [] = {0, 0, 0, -1, -1, -1, + 0, 0, 0, 1, 1, 1, + -1, -1, -1, 0, 0, 0, + 0, 0, 0, 0, 0, -1, 1, -1 + }; + + const string atomsP2[] = {"HA", "C", "CB", "HA", "C", "CB", + "HA", "N", "CB", "HA", "N", "CB", + "HA", "N", "CB", "HA", "N", "CB", + "HA", "N", "C", "C", "N", "CA", "CA", "CA" + }; const int resOffsetP2 [] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, 0, 0, 0, -1, 1, 0, 0, 1}; - vector<string> chains; + vector<string> chains; pdb.getChainNames( chains ); unsigned old_size=0; - for(unsigned s=0; s<atom.size(); s++){ - AtomNumber astart, aend; + for(unsigned s=0; s<atom.size(); s++) { + AtomNumber astart, aend; string errmsg; pdb.getAtomRange( chains[s], astart, aend, errmsg ); unsigned atom_offset = astart.index(); - for(unsigned a=1; a<atom[s].size()-1; a++){ + for(unsigned a=1; a<atom[s].size()-1; a++) { vector<AtomNumber> atm_curr = pdb.getAtomsInResidue(atom[s][a].fd,chains[s]); vector<AtomNumber> atm_prev = pdb.getAtomsInResidue(atom[s][a].fd-1,chains[s]); vector<AtomNumber> atm_next = pdb.getAtomsInResidue(atom[s][a].fd+1,chains[s]); - for(unsigned q=0;q<db.get_numXtraDists()-1; q++){ + for(unsigned q=0; q<db.get_numXtraDists()-1; q++) { vector<AtomNumber>::iterator at1, at1_end; vector<AtomNumber>::iterator at2, at2_end; @@ -1449,37 +1454,37 @@ void CS2Backbone::init_xdist(const PDB &pdb){ bool init_p2=false; AtomNumber p2; - if(resOffsetP1[q]== 0){ at1 = atm_curr.begin(); at1_end = atm_curr.end();} - if(resOffsetP1[q]==-1){ at1 = atm_prev.begin(); at1_end = atm_prev.end();} - if(resOffsetP1[q]==+1){ at1 = atm_next.begin(); at1_end = atm_next.end();} - while(at1!=at1_end){ + if(resOffsetP1[q]== 0) { at1 = atm_curr.begin(); at1_end = atm_curr.end();} + if(resOffsetP1[q]==-1) { at1 = atm_prev.begin(); at1_end = atm_prev.end();} + if(resOffsetP1[q]==+1) { at1 = atm_next.begin(); at1_end = atm_next.end();} + while(at1!=at1_end) { AtomNumber aa = *at1; ++at1; string name = pdb.getAtomName(aa); xdist_name_map(name); - if(name==atomsP1[q]){ - p1 = aa; + if(name==atomsP1[q]) { + p1 = aa; init_p1=true; - break; + break; } } - if(resOffsetP2[q]== 0){ at2 = atm_curr.begin(); at2_end = atm_curr.end();} - if(resOffsetP2[q]==-1){ at2 = atm_prev.begin(); at2_end = atm_prev.end();} - if(resOffsetP2[q]==+1){ at2 = atm_next.begin(); at2_end = atm_next.end();} - while(at2!=at2_end){ + if(resOffsetP2[q]== 0) { at2 = atm_curr.begin(); at2_end = atm_curr.end();} + if(resOffsetP2[q]==-1) { at2 = atm_prev.begin(); at2_end = atm_prev.end();} + if(resOffsetP2[q]==+1) { at2 = atm_next.begin(); at2_end = atm_next.end();} + while(at2!=at2_end) { AtomNumber aa = *at2; ++at2; string name = pdb.getAtomName(aa); xdist_name_map(name); - if(name==atomsP2[q]){ - p2 = aa; + if(name==atomsP2[q]) { + p2 = aa; init_p2=true; - break; + break; } } int add1 = -1; @@ -1490,13 +1495,13 @@ void CS2Backbone::init_xdist(const PDB &pdb){ atom[s][a].xd2.push_back(add2); } } - old_size += aend.index()+1; + old_size += aend.index()+1; } } -void CS2Backbone::init_types(const PDB &pdb){ +void CS2Backbone::init_types(const PDB &pdb) { vector<AtomNumber> aa = pdb.getAtomNumbers(); - for(unsigned i=0;i<aa.size();i++){ + for(unsigned i=0; i<aa.size(); i++) { unsigned frag = pdb.getResidueNumber(aa[i]); string fragName = pdb.getResidueName(aa[i]); string atom_name = pdb.getAtomName(aa[i]); @@ -1504,14 +1509,14 @@ void CS2Backbone::init_types(const PDB &pdb){ if(isdigit(atom_name[0])) atom_type = atom_name[1]; res_num.push_back(frag); unsigned t = 0; - if (!isSP2(fragName, atom_name)){ + if (!isSP2(fragName, atom_name)) { if (atom_type == 'C') t = D_C; else if (atom_type == 'O') t = D_O; else if (atom_type == 'H') t = D_H; else if (atom_type == 'N') t = D_N; else if (atom_type == 'S') t = D_S; else plumed_merror("CS2Backbone:init_type: unknown atom type!\n"); - }else{ + } else { if (atom_type == 'C') t = D_C2; else if (atom_type == 'O') t = D_O2; else if (atom_type == 'N') t = D_N2; @@ -1521,24 +1526,24 @@ void CS2Backbone::init_types(const PDB &pdb){ } } -void CS2Backbone::init_rings(const PDB &pdb){ +void CS2Backbone::init_rings(const PDB &pdb) { const string pheTyr_n[] = {"CG","CD1","CE1","CZ","CE2","CD2"}; const string trp1_n[] = {"CD2","CE2","CZ2","CH2","CZ3","CE3"}; const string trp2_n[] = {"CG","CD1","NE1","CE2","CD2"}; const string his_n[] = {"CG","ND1","CD2","CE1","NE2"}; - vector<string> chains; + vector<string> chains; pdb.getChainNames( chains ); vector<AtomNumber> allatoms = pdb.getAtomNumbers(); unsigned old_size=0; - for(unsigned s=0; s<atom.size(); s++){ - AtomNumber astart, aend; + for(unsigned s=0; s<atom.size(); s++) { + AtomNumber astart, aend; string errmsg; pdb.getAtomRange( chains[s], astart, aend, errmsg ); unsigned atom_offset = astart.index(); - for(unsigned r=0; r<atom[s].size(); r++){ + for(unsigned r=0; r<atom[s].size(); r++) { string frg = pdb.getResidueName(atom[s][r].fd); if(!((frg=="PHE")||(frg=="TYR")||(frg=="TRP")|| (frg=="HIS")||(frg=="HIP")||(frg=="HID")|| @@ -1547,14 +1552,14 @@ void CS2Backbone::init_rings(const PDB &pdb){ vector<AtomNumber> frg_atoms = pdb.getAtomsInResidue(atom[s][r].fd,chains[s]); - if(frg=="PHE"||frg=="TYR"){ + if(frg=="PHE"||frg=="TYR") { RingInfo ri; - for(unsigned a=0;a<frg_atoms.size();a++){ + for(unsigned a=0; a<frg_atoms.size(); a++) { unsigned atm = frg_atoms[a].index()-atom_offset+old_size; - for(unsigned aa=0;aa<6;aa++){ - if(pdb.getAtomName(frg_atoms[a])==pheTyr_n[aa]){ - ri.atom[aa] = atm; - break; + for(unsigned aa=0; aa<6; aa++) { + if(pdb.getAtomName(frg_atoms[a])==pheTyr_n[aa]) { + ri.atom[aa] = atm; + break; } } } @@ -1563,13 +1568,13 @@ void CS2Backbone::init_rings(const PDB &pdb){ if(frg=="TYR") ri.rtype = RingInfo::R_TYR; ringInfo.push_back(ri); - } else if(frg=="TRP"){ + } else if(frg=="TRP") { //First ring RingInfo ri; - for(unsigned a=0;a<frg_atoms.size();a++){ + for(unsigned a=0; a<frg_atoms.size(); a++) { unsigned atm = frg_atoms[a].index()-atom_offset+old_size; - for(unsigned aa=0;aa<6;aa++){ - if(pdb.getAtomName(frg_atoms[a])==trp1_n[aa]){ + for(unsigned aa=0; aa<6; aa++) { + if(pdb.getAtomName(frg_atoms[a])==trp1_n[aa]) { ri.atom[aa] = atm; break; } @@ -1580,10 +1585,10 @@ void CS2Backbone::init_rings(const PDB &pdb){ ringInfo.push_back(ri); //Second Ring RingInfo ri2; - for(unsigned a=0;a<frg_atoms.size();a++){ + for(unsigned a=0; a<frg_atoms.size(); a++) { unsigned atm = frg_atoms[a].index()-atom_offset+old_size; - for(unsigned aa=0;aa<5;aa++){ - if(pdb.getAtomName(frg_atoms[a])==trp2_n[aa]){ + for(unsigned aa=0; aa<5; aa++) { + if(pdb.getAtomName(frg_atoms[a])==trp2_n[aa]) { ri2.atom[aa] = atm; break; } @@ -1597,12 +1602,12 @@ void CS2Backbone::init_rings(const PDB &pdb){ (frg=="HIE")||(frg=="HSD")||(frg=="HSE")|| (frg=="HSP")) {//HIS case RingInfo ri; - for(unsigned a=0;a<frg_atoms.size();a++){ + for(unsigned a=0; a<frg_atoms.size(); a++) { unsigned atm = frg_atoms[a].index()-atom_offset+old_size; - for(unsigned aa=0;aa<5;aa++){ - if(pdb.getAtomName(frg_atoms[a])==his_n[aa]){ - ri.atom[aa] = atm; - break; + for(unsigned aa=0; aa<5; aa++) { + if(pdb.getAtomName(frg_atoms[a])==his_n[aa]) { + ri.atom[aa] = atm; + break; } } } @@ -1613,7 +1618,7 @@ void CS2Backbone::init_rings(const PDB &pdb){ plumed_merror("Unkwown Ring Fragment"); } } - old_size += aend.index()+1; + old_size += aend.index()+1; } } @@ -1654,16 +1659,16 @@ CS2Backbone::aa_t CS2Backbone::frag2enum(const string &aa) { return type; } -vector<string> CS2Backbone::side_chain_atoms(const string &s){ +vector<string> CS2Backbone::side_chain_atoms(const string &s) { vector<string> sc; - if(s=="ALA"){ + if(s=="ALA") { sc.push_back( "CB" ); sc.push_back( "HB1" ); sc.push_back( "HB2" ); sc.push_back( "HB3" ); return sc; - } else if(s=="ARG"){ + } else if(s=="ARG") { sc.push_back( "CB" ); sc.push_back( "CG" ); sc.push_back( "CD" ); @@ -1691,7 +1696,7 @@ vector<string> CS2Backbone::side_chain_atoms(const string &s){ sc.push_back( "1HH2" ); sc.push_back( "2HH2" ); return sc; - } else if(s=="ASN"){ + } else if(s=="ASN") { sc.push_back( "CB" ); sc.push_back( "CG" ); sc.push_back( "OD1" ); @@ -1704,7 +1709,7 @@ vector<string> CS2Backbone::side_chain_atoms(const string &s){ sc.push_back( "1HD2" ); sc.push_back( "2HD2" ); return sc; - } else if(s=="ASP"||s=="ASH"){ + } else if(s=="ASP"||s=="ASH") { sc.push_back( "CB" ); sc.push_back( "CG" ); sc.push_back( "OD1" ); @@ -1713,7 +1718,7 @@ vector<string> CS2Backbone::side_chain_atoms(const string &s){ sc.push_back( "HB2" ); sc.push_back( "HB3" ); return sc; - } else if(s=="CYS"||s=="CYM"){ + } else if(s=="CYS"||s=="CYM") { sc.push_back( "CB" ); sc.push_back( "SG" ); sc.push_back( "HB1" ); @@ -1722,7 +1727,7 @@ vector<string> CS2Backbone::side_chain_atoms(const string &s){ sc.push_back( "HG1" ); sc.push_back( "HG" ); return sc; - } else if(s=="GLN"){ + } else if(s=="GLN") { sc.push_back( "CB" ); sc.push_back( "CG" ); sc.push_back( "CD" ); @@ -1739,7 +1744,7 @@ vector<string> CS2Backbone::side_chain_atoms(const string &s){ sc.push_back( "1HE2" ); sc.push_back( "2HE2" ); return sc; - } else if(s=="GLU"||s=="GLH"){ + } else if(s=="GLU"||s=="GLH") { sc.push_back( "CB" ); sc.push_back( "CG" ); sc.push_back( "CD" ); @@ -1752,10 +1757,10 @@ vector<string> CS2Backbone::side_chain_atoms(const string &s){ sc.push_back( "HG2" ); sc.push_back( "HG3" ); return sc; - } else if(s=="GLY"){ + } else if(s=="GLY") { sc.push_back( "HA2" ); return sc; - } else if(s=="HIS"||s=="HSE"||s=="HIE"||s=="HSD"||s=="HID"||s=="HIP"||s=="HSP"){ + } else if(s=="HIS"||s=="HSE"||s=="HIE"||s=="HSD"||s=="HID"||s=="HIP"||s=="HSP") { sc.push_back( "CB" ); sc.push_back( "CG" ); sc.push_back( "ND1" ); @@ -1770,7 +1775,7 @@ vector<string> CS2Backbone::side_chain_atoms(const string &s){ sc.push_back( "HE1" ); sc.push_back( "HE2" ); return sc; - } else if(s=="ILE"){ + } else if(s=="ILE") { sc.push_back( "CB" ); sc.push_back( "CG1" ); sc.push_back( "CG2" ); @@ -1790,7 +1795,7 @@ vector<string> CS2Backbone::side_chain_atoms(const string &s){ sc.push_back( "HD2" ); sc.push_back( "HD3" ); return sc; - } else if(s=="LEU"){ + } else if(s=="LEU") { sc.push_back( "CB" ); sc.push_back( "CG" ); sc.push_back( "CD1" ); @@ -1812,7 +1817,7 @@ vector<string> CS2Backbone::side_chain_atoms(const string &s){ sc.push_back( "2HD2" ); sc.push_back( "3HD2" ); return sc; - } else if(s=="LYS"){ + } else if(s=="LYS") { sc.push_back( "CB" ); sc.push_back( "CG" ); sc.push_back( "CD" ); @@ -1834,7 +1839,7 @@ vector<string> CS2Backbone::side_chain_atoms(const string &s){ sc.push_back( "HZ2" ); sc.push_back( "HZ3" ); return sc; - } else if(s=="MET"){ + } else if(s=="MET") { sc.push_back( "CB" ); sc.push_back( "CG" ); sc.push_back( "SD" ); @@ -1849,7 +1854,7 @@ vector<string> CS2Backbone::side_chain_atoms(const string &s){ sc.push_back( "HE2" ); sc.push_back( "HE3" ); return sc; - } else if(s=="PHE"){ + } else if(s=="PHE") { sc.push_back( "CB" ); sc.push_back( "CG" ); sc.push_back( "CD1" ); @@ -1868,7 +1873,7 @@ vector<string> CS2Backbone::side_chain_atoms(const string &s){ sc.push_back( "HE3" ); sc.push_back( "HZ" ); return sc; - } else if(s=="PRO"){ + } else if(s=="PRO") { sc.push_back( "CB" ); sc.push_back( "CG" ); sc.push_back( "CD" ); @@ -1882,7 +1887,7 @@ vector<string> CS2Backbone::side_chain_atoms(const string &s){ sc.push_back( "HD2" ); sc.push_back( "HD3" ); return sc; - } else if(s=="SER"){ + } else if(s=="SER") { sc.push_back( "CB" ); sc.push_back( "OG" ); sc.push_back( "HB1" ); @@ -1891,7 +1896,7 @@ vector<string> CS2Backbone::side_chain_atoms(const string &s){ sc.push_back( "HG1" ); sc.push_back( "HG" ); return sc; - } else if(s=="THR"){ + } else if(s=="THR") { sc.push_back( "CB" ); sc.push_back( "OG1" ); sc.push_back( "CG2" ); @@ -1904,7 +1909,7 @@ vector<string> CS2Backbone::side_chain_atoms(const string &s){ sc.push_back( "2HG2" ); sc.push_back( "3HG2" ); return sc; - } else if(s=="TRP"){ + } else if(s=="TRP") { sc.push_back( "CB" ); sc.push_back( "CG" ); sc.push_back( "CD1" ); @@ -1925,7 +1930,7 @@ vector<string> CS2Backbone::side_chain_atoms(const string &s){ sc.push_back( "HZ3" ); sc.push_back( "HH2" ); return sc; - } else if(s=="TYR"){ + } else if(s=="TYR") { sc.push_back( "CB" ); sc.push_back( "CG" ); sc.push_back( "CD1" ); @@ -1945,7 +1950,7 @@ vector<string> CS2Backbone::side_chain_atoms(const string &s){ sc.push_back( "HE3" ); sc.push_back( "HH" ); return sc; - } else if(s=="VAL"){ + } else if(s=="VAL") { sc.push_back( "CB" ); sc.push_back( "CG1" ); sc.push_back( "CG2" ); @@ -2023,7 +2028,7 @@ bool CS2Backbone::isSP2(const string & resType, const string & atomName) { else if (atomName == "CE1") sp2 = true; else if (atomName == "CE2") sp2 = true; else if (atomName == "CZ") sp2 = true; - + } else if (resType == "ASN") { if (atomName == "CG") sp2 = true; @@ -2039,7 +2044,7 @@ bool CS2Backbone::isSP2(const string & resType, const string & atomName) { return sp2; } -bool CS2Backbone::is_chi1_cx(const string & frg, const string & atm){ +bool CS2Backbone::is_chi1_cx(const string & frg, const string & atm) { if(atm=="CG") return true; if((frg == "CYS")&&(atm =="SG")) return true; if(((frg == "ILE")||(frg == "VAL"))&&(atm == "CG1")) return true; @@ -2049,52 +2054,52 @@ bool CS2Backbone::is_chi1_cx(const string & frg, const string & atm){ return false; } -unsigned CS2Backbone::frag_segment(const unsigned p){ +unsigned CS2Backbone::frag_segment(const unsigned p) { unsigned s = 0; - for(unsigned i=0;i<seg_last.size()-1;i++){ + for(unsigned i=0; i<seg_last.size()-1; i++) { if(p>seg_last[i]) s = i+1; else break; } return s; } -unsigned CS2Backbone::frag_relitive_index(const unsigned p, const unsigned s){ +unsigned CS2Backbone::frag_relitive_index(const unsigned p, const unsigned s) { if(s==0) return p; return p-seg_last[s-1]; } -void CS2Backbone::debug_report(){ +void CS2Backbone::debug_report() { printf("\t CS2Backbone Initialization report: \n"); printf("\t -------------------------------\n"); printf("\t Number of segments: %u\n", static_cast<unsigned>(atom.size())); printf("\t Segments size: "); - for(unsigned i=0;i<atom.size();i++) printf("%u ", static_cast<unsigned>(atom[i].size())); printf("\n"); + for(unsigned i=0; i<atom.size(); i++) printf("%u ", static_cast<unsigned>(atom[i].size())); printf("\n"); printf("\t%8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s \n", - "Seg","N","AA","Prev","Curr","Next","SC","XD1","XD2","Phi","Psi","Chi1"); - for(unsigned i=0;i<atom.size();i++){ - for(unsigned j=0;j<atom[i].size();j++){ + "Seg","N","AA","Prev","Curr","Next","SC","XD1","XD2","Phi","Psi","Chi1"); + for(unsigned i=0; i<atom.size(); i++) { + for(unsigned j=0; j<atom[i].size(); j++) { printf("\t%8u %8u %8s %8u %8u %8u %8u %8u %8u %8u %8u %8u \n", - i+1, j+1, - atom[i][j].res_name.c_str(), - (unsigned)atom[i][j].prev.size(), - (unsigned)atom[i][j].curr.size(), - (unsigned)atom[i][j].next.size(), - (unsigned)atom[i][j].side_chain.size(), - (unsigned)atom[i][j].xd1.size(), - (unsigned)atom[i][j].xd2.size(), - (unsigned)atom[i][j].phi.size(), - (unsigned)atom[i][j].psi.size(), - (unsigned)atom[i][j].chi1.size()); - - for(unsigned k=0;k<atom[i][j].prev.size();k++) printf("%8i ", atom[i][j].prev[k]); printf("\n"); - for(unsigned k=0;k<atom[i][j].curr.size();k++) printf("%8i ", atom[i][j].curr[k]); printf("\n"); - for(unsigned k=0;k<atom[i][j].next.size();k++) printf("%8i ", atom[i][j].next[k]); printf("\n"); - for(unsigned k=0;k<atom[i][j].side_chain.size();k++) printf("%8i ", atom[i][j].side_chain[k]); printf("\n"); - for(unsigned k=0;k<atom[i][j].xd1.size();k++) printf("%8i ", atom[i][j].xd1[k]); printf("\n"); - for(unsigned k=0;k<atom[i][j].xd2.size();k++) printf("%8i ", atom[i][j].xd2[k]); printf("\n"); - for(unsigned k=0;k<atom[i][j].phi.size();k++) printf("%8i ", atom[i][j].phi[k]); printf("\n"); - for(unsigned k=0;k<atom[i][j].psi.size();k++) printf("%8i ", atom[i][j].psi[k]); printf("\n"); - for(unsigned k=0;k<atom[i][j].chi1.size();k++) printf("%8i ", atom[i][j].chi1[k]); printf("\n"); + i+1, j+1, + atom[i][j].res_name.c_str(), + (unsigned)atom[i][j].prev.size(), + (unsigned)atom[i][j].curr.size(), + (unsigned)atom[i][j].next.size(), + (unsigned)atom[i][j].side_chain.size(), + (unsigned)atom[i][j].xd1.size(), + (unsigned)atom[i][j].xd2.size(), + (unsigned)atom[i][j].phi.size(), + (unsigned)atom[i][j].psi.size(), + (unsigned)atom[i][j].chi1.size()); + + for(unsigned k=0; k<atom[i][j].prev.size(); k++) printf("%8i ", atom[i][j].prev[k]); printf("\n"); + for(unsigned k=0; k<atom[i][j].curr.size(); k++) printf("%8i ", atom[i][j].curr[k]); printf("\n"); + for(unsigned k=0; k<atom[i][j].next.size(); k++) printf("%8i ", atom[i][j].next[k]); printf("\n"); + for(unsigned k=0; k<atom[i][j].side_chain.size(); k++) printf("%8i ", atom[i][j].side_chain[k]); printf("\n"); + for(unsigned k=0; k<atom[i][j].xd1.size(); k++) printf("%8i ", atom[i][j].xd1[k]); printf("\n"); + for(unsigned k=0; k<atom[i][j].xd2.size(); k++) printf("%8i ", atom[i][j].xd2[k]); printf("\n"); + for(unsigned k=0; k<atom[i][j].phi.size(); k++) printf("%8i ", atom[i][j].phi[k]); printf("\n"); + for(unsigned k=0; k<atom[i][j].psi.size(); k++) printf("%8i ", atom[i][j].psi[k]); printf("\n"); + for(unsigned k=0; k<atom[i][j].chi1.size(); k++) printf("%8i ", atom[i][j].chi1[k]); printf("\n"); } } @@ -2103,16 +2108,16 @@ void CS2Backbone::debug_report(){ printf("\t ------ \n"); printf("\t Number of rings: %u\n", static_cast<unsigned>(ringInfo.size())); printf("\t%8s %8s %8s %8s\n", "Num","Type","RType","N.atoms"); - for(unsigned i=0;i<ringInfo.size();i++){ + for(unsigned i=0; i<ringInfo.size(); i++) { printf("\t%8u %8u %8u \n",i+1,ringInfo[i].rtype,ringInfo[i].numAtoms); - for(unsigned j=0;j<ringInfo[i].numAtoms;j++) printf("%8u ", ringInfo[i].atom[j]); printf("\n"); - } + for(unsigned j=0; j<ringInfo[i].numAtoms; j++) printf("%8u ", ringInfo[i].atom[j]); printf("\n"); + } } -void CS2Backbone::xdist_name_map(string & name){ +void CS2Backbone::xdist_name_map(string & name) { if((name == "OT1")||(name == "OC1")) name = "O"; else if ((name == "HN") || (name == "HT1") || (name == "H1")) name = "H"; - else if ((name == "CG1")|| (name == "OG")|| + else if ((name == "CG1")|| (name == "OG")|| (name == "SG") || (name == "OG1")) name = "CG"; else if ((name == "HA1")) name = "HA"; } diff --git a/src/colvar/Cell.cpp b/src/colvar/Cell.cpp index 92229d790..5c59e9f49 100644 --- a/src/colvar/Cell.cpp +++ b/src/colvar/Cell.cpp @@ -27,8 +27,8 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { //+PLUMEDOC COLVAR CELL /* @@ -63,7 +63,7 @@ public: PLUMED_REGISTER_ACTION(Cell,"CELL") Cell::Cell(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao) + PLUMED_COLVAR_INIT(ao) { std::vector<AtomNumber> atoms; checkRead(); @@ -80,7 +80,7 @@ PLUMED_COLVAR_INIT(ao) requestAtoms(atoms); } -void Cell::registerKeywords( Keywords& keys ){ +void Cell::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionWithValue::registerKeywords( keys ); ActionAtomistic::registerKeywords( keys ); @@ -98,13 +98,13 @@ void Cell::registerKeywords( Keywords& keys ){ // calculator -void Cell::calculate(){ +void Cell::calculate() { - for(int i=0;i<3;i++) for(int j=0;j<3;j++) components[i][j]->set(getBox()[i][j]); - for(int l=0;l<3;l++) for(int m=0;m<3;m++){ - Tensor der; for(int i=0;i<3;i++) der[i][m]=getBox()[l][i]; - setBoxDerivatives(components[l][m],-der); - } + for(int i=0; i<3; i++) for(int j=0; j<3; j++) components[i][j]->set(getBox()[i][j]); + for(int l=0; l<3; l++) for(int m=0; m<3; m++) { + Tensor der; for(int i=0; i<3; i++) der[i][m]=getBox()[l][i]; + setBoxDerivatives(components[l][m],-der); + } } } diff --git a/src/colvar/Colvar.h b/src/colvar/Colvar.h index aead24e9b..2d8904d64 100644 --- a/src/colvar/Colvar.h +++ b/src/colvar/Colvar.h @@ -22,11 +22,11 @@ #ifndef __PLUMED_colvar_Colvar_h #define __PLUMED_colvar_Colvar_h #include "core/Colvar.h" -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { // Ideally core/Colvar.h should be moved to this directory and Colvar should stay in namespace PLMD::colvar // With this trick, PLMD::Colvar is visible as PLMD::colvar::Colvar - using PLMD::Colvar; +using PLMD::Colvar; } } #endif diff --git a/src/colvar/Constant.cpp b/src/colvar/Constant.cpp index 15bdab0df..49423413d 100644 --- a/src/colvar/Constant.cpp +++ b/src/colvar/Constant.cpp @@ -27,8 +27,8 @@ #include <string> #include <cmath> -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { //+PLUMEDOC COLVAR CONSTANT /* @@ -76,16 +76,16 @@ public: PLUMED_REGISTER_ACTION(Constant,"CONSTANT") Constant::Constant(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao) + PLUMED_COLVAR_INIT(ao) { bool noderiv=false; parseFlag("NODERIV",noderiv); parseVector("VALUES",values); - if(values.size()==0){ + if(values.size()==0) { double v; parse("VALUE",v); // this checks if v is different from NAN - if(v*2!=v || v==0.0){ + if(v*2!=v || v==0.0) { values.resize(1); values[0]=v; } @@ -98,7 +98,7 @@ PLUMED_COLVAR_INIT(ao) setNotPeriodic(); setValue(values[0]); } else if(values.size()>1) { - for(unsigned i=0;i<values.size();i++) { + for(unsigned i=0; i<values.size(); i++) { std::string num; Tools::convert(i,num); if(!noderiv) addComponentWithDerivatives("v_"+num); else addComponent("v_"+num); @@ -112,24 +112,24 @@ PLUMED_COLVAR_INIT(ao) requestAtoms(atoms); } -void Constant::registerKeywords( Keywords& keys ){ +void Constant::registerKeywords( Keywords& keys ) { Colvar::registerKeywords( keys ); componentsAreNotOptional(keys); useCustomisableComponents(keys); - keys.remove("NUMERICAL_DERIVATIVES"); + keys.remove("NUMERICAL_DERIVATIVES"); keys.add("compulsory","VALUES","NAN","The values of the constants"); keys.add("compulsory","VALUE","NAN","The value of the constant"); - keys.addFlag("NODERIV",false,"Set to TRUE if you want values without derivatives."); - keys.addOutputComponent("v","default","the # value"); + keys.addFlag("NODERIV",false,"Set to TRUE if you want values without derivatives."); + keys.addOutputComponent("v","default","the # value"); } // calculator -void Constant::calculate(){ - if(values.size()==1) { +void Constant::calculate() { + if(values.size()==1) { setValue(values[0]); return; } - for(unsigned i=0;i<values.size();i++) { + for(unsigned i=0; i<values.size(); i++) { Value* comp=getPntrToComponent(i); comp->set(values[i]); } diff --git a/src/colvar/ContactMap.cpp b/src/colvar/ContactMap.cpp index 4cb1c84b9..9405f172f 100644 --- a/src/colvar/ContactMap.cpp +++ b/src/colvar/ContactMap.cpp @@ -53,15 +53,15 @@ PRINT ARG=f1.* FILE=colvar The following example calculates the difference of the current contact map with respect to a reference provided. In this case REFERENCE is the fraction of contact that is formed (i.e. the distance between two atoms transformed with the SWITH), while R_0 is the contact -distance. WEIGHT gives the relative weight of each contact to the final distance measure. +distance. WEIGHT gives the relative weight of each contact to the final distance measure. \verbatim CONTACTMAP ... -ATOMS1=1,2 REFERENCE1=0.1 WEIGHT1=0.5 -ATOMS2=3,4 REFERENCE2=0.5 WEIGHT2=1.0 -ATOMS3=4,5 REFERENCE3=0.25 WEIGHT3=1.0 -ATOMS4=5,6 REFERENCE4=0.0 WEIGHT4=0.5 -SWITCH={RATIONAL R_0=1.5} +ATOMS1=1,2 REFERENCE1=0.1 WEIGHT1=0.5 +ATOMS2=3,4 REFERENCE2=0.5 WEIGHT2=1.0 +ATOMS3=4,5 REFERENCE3=0.25 WEIGHT3=1.0 +ATOMS4=5,6 REFERENCE4=0.0 WEIGHT4=0.5 +SWITCH={RATIONAL R_0=1.5} LABEL=cmap CMDIST ... CONTACTMAP @@ -69,14 +69,14 @@ CMDIST PRINT ARG=cmap FILE=colvar \endverbatim -The next example calculates calculates fraction of native contacts (Q) -for Trp-cage mini-protein. R_0 is the distance at which the switch function is guaranteed to -be 1.0 – it doesn't really matter for Q and should be something very small, like 1 A. -REF is the reference distance for the contact, e.g. the distance from a crystal structure. -LAMBDA is the tolerance for the distance – if set to 1.0, the contact would have to have exactly -the reference value to be formed; instead for lambda values of 1.5–1.8 are usually used to allow some slack. -BETA is the softness of the switch function, default is 50nm. -WEIGHT is the 1/(number of contacts) giving equal weight to each contact. +The next example calculates calculates fraction of native contacts (Q) +for Trp-cage mini-protein. R_0 is the distance at which the switch function is guaranteed to +be 1.0 – it doesn't really matter for Q and should be something very small, like 1 A. +REF is the reference distance for the contact, e.g. the distance from a crystal structure. +LAMBDA is the tolerance for the distance – if set to 1.0, the contact would have to have exactly +the reference value to be formed; instead for lambda values of 1.5–1.8 are usually used to allow some slack. +BETA is the softness of the switch function, default is 50nm. +WEIGHT is the 1/(number of contacts) giving equal weight to each contact. When using native contact Q switch function, please cite \cite best2013 @@ -87,7 +87,7 @@ CONTACTMAP ... ATOMS1=1,67 SWITCH1={Q R_0=0.01 BETA=50.0 LAMBDA=1.5 REF=0.4059} WEIGHT1=0.003597 ATOMS2=1,68 SWITCH2={Q R_0=0.01 BETA=50.0 LAMBDA=1.5 REF=0.4039} WEIGHT2=0.003597 ATOMS3=1,69 SWITCH3={Q R_0=0.01 BETA=50.0 LAMBDA=1.5 REF=0.3215} WEIGHT3=0.003597 -[snip] +[snip] ATOMS275=183,213 SWITCH275={Q R_0=0.01 BETA=50.0 LAMBDA=1.5 REF=0.355} WEIGHT275=0.003597 ATOMS276=183,234 SWITCH276={Q R_0=0.01 BETA=50.0 LAMBDA=1.5 REF=0.428} WEIGHT276=0.003597 ATOMS277=183,250 SWITCH277={Q R_0=0.01 BETA=50.0 LAMBDA=1.5 REF=0.3832} WEIGHT277=0.003597 @@ -104,7 +104,7 @@ PRINT ARG=cmap FILE=colvar */ //+ENDPLUMEDOC -class ContactMap : public Colvar { +class ContactMap : public Colvar { private: bool pbc, serial, docomp, dosum, docmdist; NeighborList *nl; @@ -116,28 +116,28 @@ public: ~ContactMap(); // active methods: virtual void calculate(); - void checkFieldsAllowed(){} + void checkFieldsAllowed() {} }; PLUMED_REGISTER_ACTION(ContactMap,"CONTACTMAP") -void ContactMap::registerKeywords( Keywords& keys ){ +void ContactMap::registerKeywords( Keywords& keys ) { Colvar::registerKeywords( keys ); keys.add("numbered","ATOMS","the atoms involved in each of the contacts you wish to calculate. " - "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one contact will be " - "calculated for each ATOM keyword you specify."); + "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one contact will be " + "calculated for each ATOM keyword you specify."); keys.reset_style("ATOMS","atoms"); keys.add("numbered","SWITCH","The switching functions to use for each of the contacts in your map. " - "You can either specify a global switching function using SWITCH or one " - "switching function for each contact. Details of the various switching " - "functions you can use are provided on \\ref switchingfunction."); + "You can either specify a global switching function using SWITCH or one " + "switching function for each contact. Details of the various switching " + "functions you can use are provided on \\ref switchingfunction."); keys.add("numbered","REFERENCE","A reference value for a given contact, by default is 0.0 " - "You can either specify a global reference value using REFERENCE or one " - "reference value for each contact."); + "You can either specify a global reference value using REFERENCE or one " + "reference value for each contact."); keys.add("numbered","WEIGHT","A weight value for a given contact, by default is 1.0 " - "You can either specify a global weight value using WEIGHT or one " - "weight value for each contact."); - keys.reset_style("SWITCH","compulsory"); + "You can either specify a global weight value using WEIGHT or one " + "weight value for each contact."); + keys.reset_style("SWITCH","compulsory"); keys.addFlag("SUM",false,"calculate the sum of all the contacts in the input"); keys.addFlag("CMDIST",false,"calculate the distance with respect to the provided reference contant map"); keys.addFlag("SERIAL",false,"Perform the calculation in serial - for debug purpose"); @@ -145,12 +145,12 @@ void ContactMap::registerKeywords( Keywords& keys ){ } ContactMap::ContactMap(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao), -pbc(true), -serial(false), -docomp(true), -dosum(false), -docmdist(false) + PLUMED_COLVAR_INIT(ao), + pbc(true), + serial(false), + docomp(true), + dosum(false), + docmdist(false) { parseFlag("SERIAL",serial); parseFlag("SUM",dosum); @@ -158,96 +158,96 @@ docmdist(false) if(docmdist==true&&dosum==true) error("You cannot use SUM and CMDIST together"); bool nopbc=!pbc; parseFlag("NOPBC",nopbc); - pbc=!nopbc; + pbc=!nopbc; // Read in the atoms std::vector<AtomNumber> t, ga_lista, gb_lista; - for(int i=1;;++i ){ - parseAtomList("ATOMS", i, t ); - if( t.empty() ) break; - - if( t.size()!=2 ){ - std::string ss; Tools::convert(i,ss); - error("ATOMS" + ss + " keyword has the wrong number of atoms"); - } - ga_lista.push_back(t[0]); gb_lista.push_back(t[1]); - t.resize(0); - - // Add a value for this contact - std::string num; Tools::convert(i,num); - if(!dosum&&!docmdist) {addComponentWithDerivatives("contact-"+num); componentIsNotPeriodic("contact-"+num);} + for(int i=1;; ++i ) { + parseAtomList("ATOMS", i, t ); + if( t.empty() ) break; + + if( t.size()!=2 ) { + std::string ss; Tools::convert(i,ss); + error("ATOMS" + ss + " keyword has the wrong number of atoms"); + } + ga_lista.push_back(t[0]); gb_lista.push_back(t[1]); + t.resize(0); + + // Add a value for this contact + std::string num; Tools::convert(i,num); + if(!dosum&&!docmdist) {addComponentWithDerivatives("contact-"+num); componentIsNotPeriodic("contact-"+num);} } // Create neighbour lists nl= new NeighborList(ga_lista,gb_lista,true,pbc,getPbc()); // Read in switching functions std::string errors; sfs.resize( ga_lista.size() ); unsigned nswitch=0; - for(unsigned i=0;i<ga_lista.size();++i){ - std::string num, sw1; Tools::convert(i+1, num); - if( !parseNumbered( "SWITCH", i+1, sw1 ) ) break; - nswitch++; sfs[i].set(sw1,errors); - if( errors.length()!=0 ) error("problem reading SWITCH" + num + " keyword : " + errors ); + for(unsigned i=0; i<ga_lista.size(); ++i) { + std::string num, sw1; Tools::convert(i+1, num); + if( !parseNumbered( "SWITCH", i+1, sw1 ) ) break; + nswitch++; sfs[i].set(sw1,errors); + if( errors.length()!=0 ) error("problem reading SWITCH" + num + " keyword : " + errors ); } - if( nswitch==0 ){ - std::string sw; parse("SWITCH",sw); - if(sw.length()==0) error("no switching function specified use SWITCH keyword"); - for(unsigned i=0;i<ga_lista.size();++i){ - sfs[i].set(sw,errors); - if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); - } - } else if( nswitch!=sfs.size() ){ - std::string num; Tools::convert(nswitch+1, num); - error("missing SWITCH" + num + " keyword"); + if( nswitch==0 ) { + std::string sw; parse("SWITCH",sw); + if(sw.length()==0) error("no switching function specified use SWITCH keyword"); + for(unsigned i=0; i<ga_lista.size(); ++i) { + sfs[i].set(sw,errors); + if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); + } + } else if( nswitch!=sfs.size() ) { + std::string num; Tools::convert(nswitch+1, num); + error("missing SWITCH" + num + " keyword"); } - // Read in reference values + // Read in reference values nswitch=0; reference.resize(ga_lista.size(), 0.); - for(unsigned i=0;i<ga_lista.size();++i){ - if( !parseNumbered( "REFERENCE", i+1, reference[i] ) ) break; - nswitch++; + for(unsigned i=0; i<ga_lista.size(); ++i) { + if( !parseNumbered( "REFERENCE", i+1, reference[i] ) ) break; + nswitch++; } - if( nswitch==0 ){ - parse("REFERENCE",reference[0]); - for(unsigned i=1;i<ga_lista.size();++i){ - reference[i]=reference[0]; - nswitch++; - } + if( nswitch==0 ) { + parse("REFERENCE",reference[0]); + for(unsigned i=1; i<ga_lista.size(); ++i) { + reference[i]=reference[0]; + nswitch++; + } } if(nswitch == 0 && docmdist) error("with CMDIST one must use REFERENCE to setup the reference contact map"); - // Read in weight values + // Read in weight values nswitch=0; weight.resize(ga_lista.size(), 1.0); - for(unsigned i=0;i<ga_lista.size();++i){ - if( !parseNumbered( "WEIGHT", i+1, weight[i] ) ) break; - nswitch++; + for(unsigned i=0; i<ga_lista.size(); ++i) { + if( !parseNumbered( "WEIGHT", i+1, weight[i] ) ) break; + nswitch++; } - if( nswitch==0 ){ - parse("WEIGHT",weight[0]); - for(unsigned i=1;i<ga_lista.size();++i){ - weight[i]=weight[0]; - } - nswitch = ga_lista.size(); + if( nswitch==0 ) { + parse("WEIGHT",weight[0]); + for(unsigned i=1; i<ga_lista.size(); ++i) { + weight[i]=weight[0]; + } + nswitch = ga_lista.size(); } - // Ouput details of all contacts - for(unsigned i=0;i<sfs.size();++i){ - log.printf(" The %uth contact is calculated from atoms : %d %d. Inflection point of switching function is at %s. Reference contact value is %f\n", - i+1, ga_lista[i].serial(), gb_lista[i].serial() , ( sfs[i].description() ).c_str(), reference[i] ); + // Ouput details of all contacts + for(unsigned i=0; i<sfs.size(); ++i) { + log.printf(" The %uth contact is calculated from atoms : %d %d. Inflection point of switching function is at %s. Reference contact value is %f\n", + i+1, ga_lista[i].serial(), gb_lista[i].serial(), ( sfs[i].description() ).c_str(), reference[i] ); } - if(dosum){ - addValueWithDerivatives(); setNotPeriodic(); - log.printf(" colvar is sum of all contacts in contact map\n"); + if(dosum) { + addValueWithDerivatives(); setNotPeriodic(); + log.printf(" colvar is sum of all contacts in contact map\n"); } - if(docmdist){ - addValueWithDerivatives(); setNotPeriodic(); - log.printf(" colvar is distance between the contact map matrix and the provided reference matrix\n"); + if(docmdist) { + addValueWithDerivatives(); setNotPeriodic(); + log.printf(" colvar is distance between the contact map matrix and the provided reference matrix\n"); } - if(dosum || docmdist) { - docomp=false; + if(dosum || docmdist) { + docomp=false; } else { serial=true; docomp=true; @@ -258,33 +258,33 @@ docmdist(false) checkRead(); } -ContactMap::~ContactMap(){ +ContactMap::~ContactMap() { delete nl; } -void ContactMap::calculate(){ - - double ncoord=0.; - Tensor virial; - std::vector<Vector> deriv(getNumberOfAtoms()); - - unsigned stride=comm.Get_size(); - unsigned rank=comm.Get_rank(); - if(serial){ - // when using components the parallelisation do not work - stride=1; - rank=0; - }else{ - stride=comm.Get_size(); - rank=comm.Get_rank(); - } - - // sum over close pairs - for(unsigned i=rank;i<nl->size();i+=stride) { +void ContactMap::calculate() { + + double ncoord=0.; + Tensor virial; + std::vector<Vector> deriv(getNumberOfAtoms()); + + unsigned stride=comm.Get_size(); + unsigned rank=comm.Get_rank(); + if(serial) { + // when using components the parallelisation do not work + stride=1; + rank=0; + } else { + stride=comm.Get_size(); + rank=comm.Get_rank(); + } + +// sum over close pairs + for(unsigned i=rank; i<nl->size(); i+=stride) { Vector distance; unsigned i0=nl->getClosePair(i).first; unsigned i1=nl->getClosePair(i).second; - if(pbc){ + if(pbc) { distance=pbcDistance(getPosition(i0),getPosition(i1)); } else { distance=delta(getPosition(i0),getPosition(i1)); @@ -294,40 +294,40 @@ void ContactMap::calculate(){ double coord = weight[i]*(sfs[i].calculate(distance.modulo(), dfunc) - reference[i]); Vector tmpder = weight[i]*dfunc*distance; Tensor tmpvir = weight[i]*dfunc*Tensor(distance,distance); - if(!docmdist) { - deriv[i0] -= tmpder; - deriv[i1] += tmpder; - virial -= tmpvir; - ncoord += coord; + if(!docmdist) { + deriv[i0] -= tmpder; + deriv[i1] += tmpder; + virial -= tmpvir; + ncoord += coord; } else { - tmpder *= 2.*coord; - tmpvir *= 2.*coord; - deriv[i0] -= tmpder; - deriv[i1] += tmpder; - virial -= tmpvir; - ncoord += coord*coord; + tmpder *= 2.*coord; + tmpvir *= 2.*coord; + deriv[i0] -= tmpder; + deriv[i1] += tmpder; + virial -= tmpvir; + ncoord += coord*coord; } if(docomp) { - Value* val=getPntrToComponent( i ); - setAtomsDerivatives( val, i0, deriv[i0] ); - setAtomsDerivatives( val, i1, deriv[i1] ); - setBoxDerivatives( val, -tmpvir ); - val->set(coord); + Value* val=getPntrToComponent( i ); + setAtomsDerivatives( val, i0, deriv[i0] ); + setAtomsDerivatives( val, i1, deriv[i1] ); + setBoxDerivatives( val, -tmpvir ); + val->set(coord); } - } - - if(!serial){ - comm.Sum(&ncoord,1); - if(!deriv.empty()) comm.Sum(&deriv[0][0],3*deriv.size()); - comm.Sum(&virial[0][0],9); - } - - if( !docomp ){ - for(unsigned i=0;i<deriv.size();++i) setAtomsDerivatives(i,deriv[i]); - setValue (ncoord); - setBoxDerivatives (virial); - } + } + + if(!serial) { + comm.Sum(&ncoord,1); + if(!deriv.empty()) comm.Sum(&deriv[0][0],3*deriv.size()); + comm.Sum(&virial[0][0],9); + } + + if( !docomp ) { + for(unsigned i=0; i<deriv.size(); ++i) setAtomsDerivatives(i,deriv[i]); + setValue (ncoord); + setBoxDerivatives (virial); + } } } diff --git a/src/colvar/Coordination.cpp b/src/colvar/Coordination.cpp index 06c49be4b..c1aa2da4f 100644 --- a/src/colvar/Coordination.cpp +++ b/src/colvar/Coordination.cpp @@ -27,8 +27,8 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { //+PLUMEDOC COLVAR COORDINATION /* @@ -51,7 +51,7 @@ but it can be changed using the optional SWITCH option. To make your calculation faster you can use a neighbor list, which makes it that only a relevant subset of the pairwise distance are calculated at every step. -If GROUPB is empty, it will sum the \f$\frac{N(N-1)}{2}\f$ pairs in GROUPA. This avoids computing +If GROUPB is empty, it will sum the \f$\frac{N(N-1)}{2}\f$ pairs in GROUPA. This avoids computing twice permuted indexes (e.g. pair (i,j) and (j,i)) thus running at twice the speed. Notice that if there are common atoms between GROUPA and GROUPB the switching function should be @@ -63,7 +63,7 @@ so that they actually count as "zero". The following example instructs plumed to calculate the total coordination number of the atoms in group 1-10 with the atoms in group 20-100. For atoms 1-10 coordination numbers are calculated that count the number of atoms from the second group that are within 0.3 nm of the central atom. A neighbour list is used to make this calculation faster, this neighbour list is updated every 100 steps. \verbatim -COORDINATION GROUPA=1-10 GROUPB=20-100 R_0=0.3 NLIST NL_CUTOFF=0.5 NL_STRIDE=100 +COORDINATION GROUPA=1-10 GROUPB=20-100 R_0=0.3 NLIST NL_CUTOFF=0.5 NL_STRIDE=100 \endverbatim The following is a dummy example which should compute the value 0 because the self interaction @@ -89,8 +89,8 @@ See also \ref PRINT and \ref COMBINE */ //+ENDPLUMEDOC - -class Coordination : public CoordinationBase{ + +class Coordination : public CoordinationBase { SwitchingFunction switchingFunction; public: @@ -102,25 +102,25 @@ public: PLUMED_REGISTER_ACTION(Coordination,"COORDINATION") -void Coordination::registerKeywords( Keywords& keys ){ +void Coordination::registerKeywords( Keywords& keys ) { CoordinationBase::registerKeywords(keys); keys.add("compulsory","NN","6","The n parameter of the switching function "); keys.add("compulsory","MM","0","The m parameter of the switching function; 0 implies 2*NN"); keys.add("compulsory","D_0","0.0","The d_0 parameter of the switching function"); keys.add("compulsory","R_0","The r_0 parameter of the switching function"); keys.add("optional","SWITCH","This keyword is used if you want to employ an alternative to the continuous swiching function defined above. " - "The following provides information on the \\ref switchingfunction that are available. " - "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); + "The following provides information on the \\ref switchingfunction that are available. " + "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); } Coordination::Coordination(const ActionOptions&ao): -Action(ao), -CoordinationBase(ao) + Action(ao), + CoordinationBase(ao) { string sw,errors; parse("SWITCH",sw); - if(sw.length()>0){ + if(sw.length()>0) { switchingFunction.set(sw,errors); if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); } else { @@ -135,13 +135,13 @@ CoordinationBase(ao) parse("MM",mm); switchingFunction.set(nn,mm,r0,d0); } - + checkRead(); log<<" contacts are counted with cutoff "<<switchingFunction.description()<<"\n"; } -double Coordination::pairing(double distance,double&dfunc,unsigned i,unsigned j)const{ +double Coordination::pairing(double distance,double&dfunc,unsigned i,unsigned j)const { (void) i; // avoid warnings (void) j; // avoid warnings return switchingFunction.calculateSqr(distance,dfunc); diff --git a/src/colvar/CoordinationBase.cpp b/src/colvar/CoordinationBase.cpp index 8997e34c4..2d1c6707a 100644 --- a/src/colvar/CoordinationBase.cpp +++ b/src/colvar/CoordinationBase.cpp @@ -28,10 +28,10 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { -void CoordinationBase::registerKeywords( Keywords& keys ){ +void CoordinationBase::registerKeywords( Keywords& keys ) { Colvar::registerKeywords(keys); keys.addFlag("SERIAL",false,"Perform the calculation in serial - for debug purpose"); keys.addFlag("PAIR",false,"Pair only 1st element of the 1st group with 1st element in the second, etc"); @@ -43,11 +43,11 @@ void CoordinationBase::registerKeywords( Keywords& keys ){ } CoordinationBase::CoordinationBase(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao), -pbc(true), -serial(false), -invalidateList(true), -firsttime(true) + PLUMED_COLVAR_INIT(ao), + pbc(true), + serial(false), + invalidateList(true), + firsttime(true) { parseFlag("SERIAL",serial); @@ -69,56 +69,56 @@ firsttime(true) double nl_cut=0.0; int nl_st=0; parseFlag("NLIST",doneigh); - if(doneigh){ - parse("NL_CUTOFF",nl_cut); - if(nl_cut<=0.0) error("NL_CUTOFF should be explicitly specified and positive"); - parse("NL_STRIDE",nl_st); - if(nl_st<=0) error("NL_STRIDE should be explicitly specified and positive"); + if(doneigh) { + parse("NL_CUTOFF",nl_cut); + if(nl_cut<=0.0) error("NL_CUTOFF should be explicitly specified and positive"); + parse("NL_STRIDE",nl_st); + if(nl_st<=0) error("NL_STRIDE should be explicitly specified and positive"); } - + addValueWithDerivatives(); setNotPeriodic(); - if(gb_lista.size()>0){ + if(gb_lista.size()>0) { if(doneigh) nl= new NeighborList(ga_lista,gb_lista,dopair,pbc,getPbc(),nl_cut,nl_st); else nl= new NeighborList(ga_lista,gb_lista,dopair,pbc,getPbc()); } else { if(doneigh) nl= new NeighborList(ga_lista,pbc,getPbc(),nl_cut,nl_st); else nl= new NeighborList(ga_lista,pbc,getPbc()); } - + requestAtoms(nl->getFullAtomList()); - + log.printf(" between two groups of %u and %u atoms\n",static_cast<unsigned>(ga_lista.size()),static_cast<unsigned>(gb_lista.size())); log.printf(" first group:\n"); - for(unsigned int i=0;i<ga_lista.size();++i){ - if ( (i+1) % 25 == 0 ) log.printf(" \n"); - log.printf(" %d", ga_lista[i].serial()); + for(unsigned int i=0; i<ga_lista.size(); ++i) { + if ( (i+1) % 25 == 0 ) log.printf(" \n"); + log.printf(" %d", ga_lista[i].serial()); } log.printf(" \n second group:\n"); - for(unsigned int i=0;i<gb_lista.size();++i){ - if ( (i+1) % 25 == 0 ) log.printf(" \n"); - log.printf(" %d", gb_lista[i].serial()); + for(unsigned int i=0; i<gb_lista.size(); ++i) { + if ( (i+1) % 25 == 0 ) log.printf(" \n"); + log.printf(" %d", gb_lista[i].serial()); } log.printf(" \n"); if(pbc) log.printf(" using periodic boundary conditions\n"); else log.printf(" without periodic boundary conditions\n"); if(dopair) log.printf(" with PAIR option\n"); - if(doneigh){ - log.printf(" using neighbor lists with\n"); - log.printf(" update every %d steps and cutoff %f\n",nl_st,nl_cut); + if(doneigh) { + log.printf(" using neighbor lists with\n"); + log.printf(" update every %d steps and cutoff %f\n",nl_st,nl_cut); } } -CoordinationBase::~CoordinationBase(){ +CoordinationBase::~CoordinationBase() { delete nl; } -void CoordinationBase::prepare(){ - if(nl->getStride()>0){ - if(firsttime || (getStep()%nl->getStride()==0)){ +void CoordinationBase::prepare() { + if(nl->getStride()>0) { + if(firsttime || (getStep()%nl->getStride()==0)) { requestAtoms(nl->getFullAtomList()); invalidateList=true; firsttime=false; - }else{ + } else { requestAtoms(nl->getReducedAtomList()); invalidateList=false; if(getExchangeStep()) error("Neighbor lists should be updated on exchange steps - choose a NL_STRIDE which divides the exchange stride!"); @@ -131,84 +131,84 @@ void CoordinationBase::prepare(){ void CoordinationBase::calculate() { - double ncoord=0.; - Tensor virial; - vector<Vector> deriv(getNumberOfAtoms()); + double ncoord=0.; + Tensor virial; + vector<Vector> deriv(getNumberOfAtoms()); // deriv.resize(getPositions().size()); - if(nl->getStride()>0 && invalidateList){ - nl->update(getPositions()); - } + if(nl->getStride()>0 && invalidateList) { + nl->update(getPositions()); + } - unsigned stride=comm.Get_size(); - unsigned rank=comm.Get_rank(); - if(serial){ - stride=1; - rank=0; - }else{ - stride=comm.Get_size(); - rank=comm.Get_rank(); - } + unsigned stride=comm.Get_size(); + unsigned rank=comm.Get_rank(); + if(serial) { + stride=1; + rank=0; + } else { + stride=comm.Get_size(); + rank=comm.Get_rank(); + } -unsigned nt=OpenMP::getNumThreads(); + unsigned nt=OpenMP::getNumThreads(); -const unsigned nn=nl->size(); + const unsigned nn=nl->size(); -if(nt*stride*10>nn) nt=nn/stride/10; -if(nt==0)nt=1; + if(nt*stride*10>nn) nt=nn/stride/10; + if(nt==0)nt=1; -#pragma omp parallel num_threads(nt) -{ - std::vector<Vector> omp_deriv(getPositions().size()); - Tensor omp_virial; + #pragma omp parallel num_threads(nt) + { + std::vector<Vector> omp_deriv(getPositions().size()); + Tensor omp_virial; -#pragma omp for reduction(+:ncoord) nowait - for(unsigned int i=rank;i<nn;i+=stride) { - - Vector distance; - unsigned i0=nl->getClosePair(i).first; - unsigned i1=nl->getClosePair(i).second; + #pragma omp for reduction(+:ncoord) nowait + for(unsigned int i=rank; i<nn; i+=stride) { - if(getAbsoluteIndex(i0)==getAbsoluteIndex(i1)) continue; + Vector distance; + unsigned i0=nl->getClosePair(i).first; + unsigned i1=nl->getClosePair(i).second; - if(pbc){ - distance=pbcDistance(getPosition(i0),getPosition(i1)); - } else { - distance=delta(getPosition(i0),getPosition(i1)); - } + if(getAbsoluteIndex(i0)==getAbsoluteIndex(i1)) continue; - double dfunc=0.; - ncoord += pairing(distance.modulo2(), dfunc,i0,i1); + if(pbc) { + distance=pbcDistance(getPosition(i0),getPosition(i1)); + } else { + distance=delta(getPosition(i0),getPosition(i1)); + } - Vector dd(dfunc*distance); - Tensor vv(dd,distance); - if(nt>1){ - omp_deriv[i0]-=dd; - omp_deriv[i1]+=dd; - omp_virial-=vv; - } else { - deriv[i0]-=dd; - deriv[i1]+=dd; - virial-=vv; - } + double dfunc=0.; + ncoord += pairing(distance.modulo2(), dfunc,i0,i1); - } -#pragma omp critical - if(nt>1){ - for(int i=0;i<getPositions().size();i++) deriv[i]+=omp_deriv[i]; - virial+=omp_virial; - } -} + Vector dd(dfunc*distance); + Tensor vv(dd,distance); + if(nt>1) { + omp_deriv[i0]-=dd; + omp_deriv[i1]+=dd; + omp_virial-=vv; + } else { + deriv[i0]-=dd; + deriv[i1]+=dd; + virial-=vv; + } + + } + #pragma omp critical + if(nt>1) { + for(int i=0; i<getPositions().size(); i++) deriv[i]+=omp_deriv[i]; + virial+=omp_virial; + } + } - if(!serial){ - comm.Sum(ncoord); - if(!deriv.empty()) comm.Sum(&deriv[0][0],3*deriv.size()); - comm.Sum(virial); - } + if(!serial) { + comm.Sum(ncoord); + if(!deriv.empty()) comm.Sum(&deriv[0][0],3*deriv.size()); + comm.Sum(virial); + } - for(unsigned i=0;i<deriv.size();++i) setAtomsDerivatives(i,deriv[i]); - setValue (ncoord); - setBoxDerivatives (virial); + for(unsigned i=0; i<deriv.size(); ++i) setAtomsDerivatives(i,deriv[i]); + setValue (ncoord); + setBoxDerivatives (virial); } } diff --git a/src/colvar/CoordinationBase.h b/src/colvar/CoordinationBase.h index 7ed867052..6b0f174cd 100644 --- a/src/colvar/CoordinationBase.h +++ b/src/colvar/CoordinationBase.h @@ -23,11 +23,11 @@ #define __PLUMED_colvar_CoordinationBase_h #include "Colvar.h" -namespace PLMD{ +namespace PLMD { class NeighborList; -namespace colvar{ +namespace colvar { class CoordinationBase : public Colvar { bool pbc; @@ -35,7 +35,7 @@ class CoordinationBase : public Colvar { NeighborList *nl; bool invalidateList; bool firsttime; - + public: explicit CoordinationBase(const ActionOptions&); ~CoordinationBase(); diff --git a/src/colvar/DHEnergy.cpp b/src/colvar/DHEnergy.cpp index 5c035b0ce..23ed21d58 100644 --- a/src/colvar/DHEnergy.cpp +++ b/src/colvar/DHEnergy.cpp @@ -31,8 +31,8 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { //+PLUMEDOC COLVAR DHENERGY /* @@ -49,7 +49,7 @@ using a Debye-Huckel approximation defined as This collective variable can be used to analyze or induce electrostatically driven reactions \cite do13jctc. Notice that the value of the DHENERGY is returned in plumed units (see \ref UNITS). -If GROUPB is empty, it will sum the N*(N-1)/2 pairs in GROUPA. This avoids computing +If GROUPB is empty, it will sum the N*(N-1)/2 pairs in GROUPA. This avoids computing twice permuted indexes (e.g. pair (i,j) and (j,i)) thus running at twice the speed. Notice that if there are common atoms between GROUPA and GROUPB their interaction is discarded. @@ -65,8 +65,8 @@ PRINT ARG=dh */ //+ENDPLUMEDOC - -class DHEnergy : public CoordinationBase{ + +class DHEnergy : public CoordinationBase { double k; // Inverse Debye screening length double constant; double epsilon; @@ -80,41 +80,41 @@ public: PLUMED_REGISTER_ACTION(DHEnergy,"DHENERGY") -void DHEnergy::registerKeywords( Keywords& keys ){ +void DHEnergy::registerKeywords( Keywords& keys ) { CoordinationBase::registerKeywords(keys); keys.add("compulsory","I","1.0","Ionic strength (M)"); keys.add("compulsory","TEMP","300.0","Simulation temperature (K)"); keys.add("compulsory","EPSILON","80.0","Dielectric constant of solvent"); } - /* - Global constants in SI unit used in this calculation: - N_A = 6.0221412927 * 10^(23) mol^(-1) : Avogadro number - q = 1.60217656535 * 10^(-19) C : proton charge - e_0 = 8.854187817620 * 10^(-12) C^2/(N*m^2) : vacuum's dielectric constant - k_B = 1.380648813 * 10^(-23) N*m/K : Boltzmann constant - In SI unit, Debye Huckel CV is defined as: - DHen = \sum_i\sum_j (q_i*q_j*q^2*N_A)/(4*pi*eps*e_0) * exp(-k*|f_ij|)/(|f_ij|) - + \sum_i\sum_j (q_i*q_j*q^2*N_A)/(4*pi*epp*e_0) * (1/|r_ij| - 1/|f_ij|) - = (q^2*N_A)/(4*pi*e_0) * \sum_i\sum_j q_i*q_j * (exp(-k*|f_ij|)/(eps*|f_ij|) + 1/epp*(1/|r_ij| - 1/|f_ij|)) - (in which |f_ij| = \sqrt(|r_ij|^2+\sigma_i*\sigma_j*exp(-|r_ij|^2/4*\sigma_i*\sigma_j)), - \sigma_i and \sigma_j are the effective Born radius.) - For an efficient calculation, we group constants and variables into groups: - constant = (q^2*N_A)/(4*pi*e_0) - tmp = 1/eps*exp(-k*|f_ij|)/(|f_ij|) + 1/epp*(1/|r_ij| - 1/|f_ij|) - - To speed up the loop calculation, constant can be modified as followed: - constant= (q^2*N_A)/(4*pi*e_0*10^(-9))*10^(-3) (kJ/mol) - = ((1.60217656535*10^(-19))^2*6.0221412927*10^(23)*10^(-3))/(4*3.14159265*8.854187817620*10^(-12)*10^(-9)) - = 138.935458111 (kJ/mol) - - */ +/* +Global constants in SI unit used in this calculation: + N_A = 6.0221412927 * 10^(23) mol^(-1) : Avogadro number + q = 1.60217656535 * 10^(-19) C : proton charge + e_0 = 8.854187817620 * 10^(-12) C^2/(N*m^2) : vacuum's dielectric constant + k_B = 1.380648813 * 10^(-23) N*m/K : Boltzmann constant +In SI unit, Debye Huckel CV is defined as: + DHen = \sum_i\sum_j (q_i*q_j*q^2*N_A)/(4*pi*eps*e_0) * exp(-k*|f_ij|)/(|f_ij|) + + \sum_i\sum_j (q_i*q_j*q^2*N_A)/(4*pi*epp*e_0) * (1/|r_ij| - 1/|f_ij|) + = (q^2*N_A)/(4*pi*e_0) * \sum_i\sum_j q_i*q_j * (exp(-k*|f_ij|)/(eps*|f_ij|) + 1/epp*(1/|r_ij| - 1/|f_ij|)) +(in which |f_ij| = \sqrt(|r_ij|^2+\sigma_i*\sigma_j*exp(-|r_ij|^2/4*\sigma_i*\sigma_j)), + \sigma_i and \sigma_j are the effective Born radius.) +For an efficient calculation, we group constants and variables into groups: + constant = (q^2*N_A)/(4*pi*e_0) + tmp = 1/eps*exp(-k*|f_ij|)/(|f_ij|) + 1/epp*(1/|r_ij| - 1/|f_ij|) + +To speed up the loop calculation, constant can be modified as followed: + constant= (q^2*N_A)/(4*pi*e_0*10^(-9))*10^(-3) (kJ/mol) + = ((1.60217656535*10^(-19))^2*6.0221412927*10^(23)*10^(-3))/(4*3.14159265*8.854187817620*10^(-12)*10^(-9)) + = 138.935458111 (kJ/mol) + +*/ DHEnergy::DHEnergy(const ActionOptions&ao): -Action(ao), -CoordinationBase(ao), -k(0.0), -constant(0.0) + Action(ao), + CoordinationBase(ao), + k(0.0), + constant(0.0) { double I,T; parse("I",I); @@ -132,9 +132,9 @@ constant(0.0) log<<" Bibliography "<<plumed.cite("Do, Carloni, Varani and Bussi, J. Chem. Theory Comput. 9, 1720 (2013)")<<" \n"; } -double DHEnergy::pairing(double distance2,double&dfunc,unsigned i,unsigned j)const{ +double DHEnergy::pairing(double distance2,double&dfunc,unsigned i,unsigned j)const { double distance=std::sqrt(distance2); - if(getAbsoluteIndex(i)==getAbsoluteIndex(j)){ + if(getAbsoluteIndex(i)==getAbsoluteIndex(j)) { dfunc=0.0; return 0.0; } diff --git a/src/colvar/DRMSD.cpp b/src/colvar/DRMSD.cpp index ef8376b42..5a3152ad4 100644 --- a/src/colvar/DRMSD.cpp +++ b/src/colvar/DRMSD.cpp @@ -29,47 +29,47 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { //+PLUMEDOC DCOLVAR DRMSD /* -Calculate the distance RMSD with respect to a reference structure. +Calculate the distance RMSD with respect to a reference structure. To calculate the root-mean-square deviation between the atoms in two configurations -you must first superimpose the two structures in some ways. Obviously, it is the internal vibrational -motions of the structure - i.e. not the translations and rotations - that are interesting. However, +you must first superimpose the two structures in some ways. Obviously, it is the internal vibrational +motions of the structure - i.e. not the translations and rotations - that are interesting. However, aligning two structures by removing the translational and rotational motions is not easy. Furthermore, in some cases there can be alignment issues caused by so-called frame-fitting problems. It is thus -often cheaper and easier to calculate the distances between all the pairs of atoms. The distance +often cheaper and easier to calculate the distances between all the pairs of atoms. The distance between the two structures, \f$\mathbf{X}^a\f$ and \f$\mathbf{X}^b\f$ can then be measured as: \f[ -d(\mathbf{X}^A, \mathbf{X}^B) = \frac{1}{N(N-1)} \sum_{i \ne j} [ d(\mathbf{x}_i^a,\mathbf{x}_j^a) - d(\mathbf{x}_i^b,\mathbf{x}_j^b) ]^2 -\f] +d(\mathbf{X}^A, \mathbf{X}^B) = \frac{1}{N(N-1)} \sum_{i \ne j} [ d(\mathbf{x}_i^a,\mathbf{x}_j^a) - d(\mathbf{x}_i^b,\mathbf{x}_j^b) ]^2 +\f] where \f$N\f$ is the number of atoms and \f$d(\mathbf{x}_i,\mathbf{x}_j)\f$ represents the distance between -atoms \f$i\f$ and \f$j\f$. Clearly, this representation of the configuration is invariant to translation and rotation. +atoms \f$i\f$ and \f$j\f$. Clearly, this representation of the configuration is invariant to translation and rotation. However, it can become expensive to calculate when the number of atoms is large. This can be resolved within the DRMSD colvar by setting LOWER_CUTOFF and UPPER_CUTOFF. These keywords ensure that only -pairs of atoms that are within a certain range are incorporated into the above sum. +pairs of atoms that are within a certain range are incorporated into the above sum. -In PDB files the atomic coordinates and box lengths should be in Angstroms unless -you are working with natural units. If you are working with natural units then the coordinates +In PDB files the atomic coordinates and box lengths should be in Angstroms unless +you are working with natural units. If you are working with natural units then the coordinates should be in your natural length unit. For more details on the PDB file format visit http://www.wwpdb.org/docs.html \par Examples The following tells plumed to calculate the distance RMSD between the positions of the atoms in the reference file and their instantaneous -position. Only pairs of atoms whose distance in the reference structure is within -0.1 and 0.8 nm are considered. +position. Only pairs of atoms whose distance in the reference structure is within +0.1 and 0.8 nm are considered. \verbatim DRMSD REFERENCE=file.pdb LOWER_CUTOFF=0.1 UPPER_CUTOFF=0.8 \endverbatim -The following tells plumed to calculate a DRMSD value for a pair of molecules. +The following tells plumed to calculate a DRMSD value for a pair of molecules. \verbatim DRMSD REFERENCE=file.pdb LOWER_CUTOFF=0.1 UPPER_CUTOFF=0.8 TYPE=INTER-DRMSD @@ -89,17 +89,17 @@ END \endverbatim In this example the INTER-DRMSD type ensures that the set of distances from which the final -quantity is computed involve one atom from each of the two molecules. If this is replaced -by INTRA-DRMSD then only those distances involving pairs of atoms that are both in the same -molecule are computed. +quantity is computed involve one atom from each of the two molecules. If this is replaced +by INTRA-DRMSD then only those distances involving pairs of atoms that are both in the same +molecule are computed. */ //+ENDPLUMEDOC - + class DRMSD : public Colvar { - bool pbc_; + bool pbc_; MultiValue myvals; ReferenceValuePack mypack; PLMD::DRMSD* drmsd_; @@ -113,36 +113,36 @@ public: PLUMED_REGISTER_ACTION(DRMSD,"DRMSD") -void DRMSD::registerKeywords(Keywords& keys){ +void DRMSD::registerKeywords(Keywords& keys) { Colvar::registerKeywords(keys); keys.add("compulsory","REFERENCE","a file in pdb format containing the reference structure and the atoms involved in the CV."); keys.add("compulsory","LOWER_CUTOFF","only pairs of atoms further than LOWER_CUTOFF are considered in the calculation."); keys.add("compulsory","UPPER_CUTOFF","only pairs of atoms closer than UPPER_CUTOFF are considered in the calculation."); keys.add("compulsory","TYPE","DRMSD","what kind of DRMSD would you like to calculate. You can use either the normal DRMSD involving all the distances between " - "the atoms in your molecule. Alternatively, if you have multiple molecules you can use the type INTER-DRMSD " - "to compute DRMSD values involving only those distances between the atoms at least two molecules or the type INTRA-DRMSD " - "to compute DRMSD values involving only those distances between atoms in the same molecule"); + "the atoms in your molecule. Alternatively, if you have multiple molecules you can use the type INTER-DRMSD " + "to compute DRMSD values involving only those distances between the atoms at least two molecules or the type INTRA-DRMSD " + "to compute DRMSD values involving only those distances between atoms in the same molecule"); } DRMSD::DRMSD(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao), pbc_(true), myvals(1,0), mypack(0,0,myvals) + PLUMED_COLVAR_INIT(ao), pbc_(true), myvals(1,0), mypack(0,0,myvals) { string reference; parse("REFERENCE",reference); - double lcutoff; + double lcutoff; parse("LOWER_CUTOFF",lcutoff); - double ucutoff; + double ucutoff; parse("UPPER_CUTOFF",ucutoff); bool nopbc(false); parseFlag("NOPBC",nopbc); pbc_=!nopbc; - addValueWithDerivatives(); setNotPeriodic(); + addValueWithDerivatives(); setNotPeriodic(); // read everything in ang and transform to nm if we are not in natural units PDB pdb; if( !pdb.read(reference,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength()) ) - error("missing input file " + reference ); + error("missing input file " + reference ); // store target_ distance std::string type; parse("TYPE",type); @@ -151,33 +151,33 @@ PLUMED_COLVAR_INIT(ao), pbc_(true), myvals(1,0), mypack(0,0,myvals) drmsd_->set( pdb ); checkRead(); - std::vector<AtomNumber> atoms; + std::vector<AtomNumber> atoms; drmsd_->getAtomRequests( atoms ); // drmsd_->setNumberOfAtoms( atoms.size() ); requestAtoms( atoms ); // Setup the derivative pack myvals.resize( 1, 3*atoms.size()+9 ); mypack.resize( 0, atoms.size() ); - for(unsigned i=0;i<atoms.size();++i) mypack.setAtomIndex( i, i ); + for(unsigned i=0; i<atoms.size(); ++i) mypack.setAtomIndex( i, i ); log.printf(" reference from file %s\n",reference.c_str()); log.printf(" which contains %d atoms\n",getNumberOfAtoms()); } -DRMSD::~DRMSD(){ +DRMSD::~DRMSD() { delete drmsd_; } // calculator -void DRMSD::calculate(){ +void DRMSD::calculate() { - double drmsd; Tensor virial; mypack.clear(); - drmsd=drmsd_->calculate(getPositions(), getPbc(), mypack, false); + double drmsd; Tensor virial; mypack.clear(); + drmsd=drmsd_->calculate(getPositions(), getPbc(), mypack, false); - setValue(drmsd); - for(unsigned i=0;i<getNumberOfAtoms();++i) { if( myvals.isActive(3*i) ) setAtomsDerivatives( i, mypack.getAtomDerivative(i) ); } - setBoxDerivatives( mypack.getBoxDerivatives() ); + setValue(drmsd); + for(unsigned i=0; i<getNumberOfAtoms(); ++i) { if( myvals.isActive(3*i) ) setAtomsDerivatives( i, mypack.getAtomDerivative(i) ); } + setBoxDerivatives( mypack.getBoxDerivatives() ); } } diff --git a/src/colvar/Dimer.cpp b/src/colvar/Dimer.cpp index 40b37ab21..827c84365 100644 --- a/src/colvar/Dimer.cpp +++ b/src/colvar/Dimer.cpp @@ -33,17 +33,17 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { //+PLUMEDOC COLVAR DIMER /* This CV computes the Dimer interaction energy for a collection of Dimers. - -Each Dimer represents an atom, as described in the Dimer paper, -JCTC 13, 425 (2017). A system of N atoms is thus represented with N Dimers, each + +Each Dimer represents an atom, as described in the Dimer paper, +JCTC 13, 425 (2017). A system of N atoms is thus represented with N Dimers, each Dimer being composed of two beads and eventually a virtual site representing its center of mass. - + A typical configuration for a dimerized system has the following ordering of atoms: 1 TAG1 X Y Z N atoms representing the first bead of each Dimer @@ -70,16 +70,16 @@ N+2 TAG2 X Y Z 3N TAGN X Y Z The configuration might go on with un-dimerized atoms (like a solvent) -3N+1 - -3N+2 - +3N+1 + +3N+2 + ... -The Dimer interaction energy is defined between atoms x and N+x, for x=1,...,N and is -characterized by two parameters Q and DSIGMA. These are passed as mandatory arguments along with -the temperature of the system. +The Dimer interaction energy is defined between atoms x and N+x, for x=1,...,N and is +characterized by two parameters Q and DSIGMA. These are passed as mandatory arguments along with +the temperature of the system. \par Examples @@ -89,25 +89,25 @@ This line tells Plumed to compute the Dimer interaction energy for every dimer i dim: DIMER TEMP=300 Q=0.5 ALLATOMS DSIGMA=0.002 \endverbatim -If the simulation doesn't use virtual sites for the dimers centers of mass, -Plumed has to know in order to determine correctly the total number of dimers from +If the simulation doesn't use virtual sites for the dimers centers of mass, +Plumed has to know in order to determine correctly the total number of dimers from the total number of atoms: \verbatim dim: DIMER TEMP=300 Q=0.5 ALLATOMS DSIGMA=0.002 NOVSITES \endverbatim -The NOVSITES flag is not required if one provides the atom serial of each Dimer. This is -defined as the atom serial of the first bead of the dimer and is thus a number between 1 and N. +The NOVSITES flag is not required if one provides the atom serial of each Dimer. This is +defined as the atom serial of the first bead of the dimer and is thus a number between 1 and N. Along with the ATOMS list also the number N of lines describing the first beads has to be given. -For example, the Dimer interaction energy of dimers 1,5,7 is: +For example, the Dimer interaction energy of dimers 1,5,7 is: \verbatim dim: DIMER TEMP=300 Q=0.5 NATOMS=N ATOMS=1,5,7 DSIGMA=0.002 \endverbatim -In a Replica Exchange simulation the keyword DSIGMA can be used in two ways: -if a plumed.n.dat file is provided for each replica, then DSIGMA is passed as a single value, -like in the previous examples, and each replica will read its own DSIGMA value. If -a unique plumed.dat is given, DSIGMA has to be a list containing a value for each replica. +In a Replica Exchange simulation the keyword DSIGMA can be used in two ways: +if a plumed.n.dat file is provided for each replica, then DSIGMA is passed as a single value, +like in the previous examples, and each replica will read its own DSIGMA value. If +a unique plumed.dat is given, DSIGMA has to be a list containing a value for each replica. For 4 replicas: \verbatim dim: DIMER TEMP=300 Q=0.5 NATOMS=N ATOMS=1,5,7 DSIGMA=0.002,0.002,0.004,0.01 @@ -116,182 +116,182 @@ dim: DIMER TEMP=300 Q=0.5 NATOMS=N ATOMS=1,5,7 DSIGMA=0.002,0.002,0.004,0.01 \par Usage of the CV -The dimer interaction is not coded in the driver program and has to be inserted +The dimer interaction is not coded in the driver program and has to be inserted in the hamiltonian of the system as a linear RESTRAINT (see \ref RESTRAINT): \verbatim dim: DIMER TEMP=300 Q=0.5 ALLATOMS DSIGMA=0.002 RESTRAINT ARG=dim AT=0 KAPPA=0 SLOPE=1 LABEL=dimforces \endverbatim -In a replica exchange, Metadynamics (see \ref METAD) can be used on the Dimer CV to reduce -the number of replicas. Just keep in mind that METAD SIGMA values should be tuned -in the standard way for each replica according to the value of DSIGMA. +In a replica exchange, Metadynamics (see \ref METAD) can be used on the Dimer CV to reduce +the number of replicas. Just keep in mind that METAD SIGMA values should be tuned +in the standard way for each replica according to the value of DSIGMA. */ //+ENDPLUMEDOC class Dimer : public Colvar { - public: - static void registerKeywords( Keywords& keys); - Dimer(const ActionOptions&); - virtual void calculate(); - protected: - bool trimer,useall; - int myrank, nranks, natoms; - double qexp,temperature,beta,dsigma; - vector<double> dsigmas; - private: - void consistencyCheck(); - vector<int> usedatoms; +public: + static void registerKeywords( Keywords& keys); + Dimer(const ActionOptions&); + virtual void calculate(); +protected: + bool trimer,useall; + int myrank, nranks, natoms; + double qexp,temperature,beta,dsigma; + vector<double> dsigmas; +private: + void consistencyCheck(); + vector<int> usedatoms; }; PLUMED_REGISTER_ACTION(Dimer, "DIMER") -void Dimer::registerKeywords( Keywords& keys){ - Colvar::registerKeywords(keys); - - keys.add("compulsory","DSIGMA","The interaction strength of the dimer bond."); - keys.add("compulsory", "Q", "The exponent of the dimer potential."); - keys.add("compulsory", "TEMP", "The temperature (in Kelvin) of the simulation."); - keys.add("atoms", "ATOMS", "The list of atoms being considered by this CV. Used if ALLATOMS flag is missing"); - keys.add("atoms","NATOMS","The number of dimerized atoms. Used in combination with ATOMS list"); - keys.addFlag("ALLATOMS", false, "Use EVERY atom of the system. Overrides ATOMS keyword."); - keys.addFlag("NOVSITES", false, "If present the configuration is without virtual sites at the centroids."); - +void Dimer::registerKeywords( Keywords& keys) { + Colvar::registerKeywords(keys); + + keys.add("compulsory","DSIGMA","The interaction strength of the dimer bond."); + keys.add("compulsory", "Q", "The exponent of the dimer potential."); + keys.add("compulsory", "TEMP", "The temperature (in Kelvin) of the simulation."); + keys.add("atoms", "ATOMS", "The list of atoms being considered by this CV. Used if ALLATOMS flag is missing"); + keys.add("atoms","NATOMS","The number of dimerized atoms. Used in combination with ATOMS list"); + keys.addFlag("ALLATOMS", false, "Use EVERY atom of the system. Overrides ATOMS keyword."); + keys.addFlag("NOVSITES", false, "If present the configuration is without virtual sites at the centroids."); + } Dimer::Dimer(const ActionOptions& ao): - PLUMED_COLVAR_INIT(ao) + PLUMED_COLVAR_INIT(ao) { - - log<<" Bibliography "<<plumed.cite("M Nava, F. Palazzesi, C. Perego and M. Parrinello, J. Chem. Theory Comput. 13, 425(2017)")<<"\n"; - parseVector("DSIGMA",dsigmas); - parse("Q",qexp); - parse("TEMP",temperature); - - - vector<AtomNumber> atoms; - parseFlag("ALLATOMS",useall); - trimer=true; - bool notrim; - parseFlag("NOVSITES",notrim); - trimer=!notrim; - - nranks=multi_sim_comm.Get_size(); - myrank=multi_sim_comm.Get_rank(); - if(dsigmas.size()==1) - dsigma=dsigmas[0]; - else - dsigma=dsigmas[myrank]; - - - - - if(useall) - { - // go with every atom in the system but not the virtuals... - if(trimer) - natoms= 2*getTotAtoms()/3; - else - natoms=getTotAtoms()/2; - - for(unsigned int i=0;i<((unsigned int)natoms);i++) - { - AtomNumber ati; - ati.setIndex(i); - atoms.push_back(ati); - } - } - else // serials for the first beads of each dimer are given - { - parseVector("ATOMS",usedatoms); - double ntm; - parse("NATOMS",ntm); - natoms=ntm; - - int isz = usedatoms.size(); - - for(unsigned int i=0;i<isz;i++) - { - AtomNumber ati; - ati.setIndex(usedatoms[i]-1); - atoms.push_back(ati); - - } - - for(unsigned int i=0;i<isz;i++) - { - AtomNumber atip2; - atip2.setIndex(usedatoms[i]+natoms-1); - if(usedatoms[i]>natoms) - error("The Dimer CV requires that when choosing atoms you refere only to the first beads."); - atoms.push_back(atip2); - } - - } - consistencyCheck(); - checkRead(); - beta = 1./(kBoltzmann*temperature); - - addValueWithDerivatives(); // allocate - - requestAtoms(atoms); - - setNotPeriodic(); - + + log<<" Bibliography "<<plumed.cite("M Nava, F. Palazzesi, C. Perego and M. Parrinello, J. Chem. Theory Comput. 13, 425(2017)")<<"\n"; + parseVector("DSIGMA",dsigmas); + parse("Q",qexp); + parse("TEMP",temperature); + + + vector<AtomNumber> atoms; + parseFlag("ALLATOMS",useall); + trimer=true; + bool notrim; + parseFlag("NOVSITES",notrim); + trimer=!notrim; + + nranks=multi_sim_comm.Get_size(); + myrank=multi_sim_comm.Get_rank(); + if(dsigmas.size()==1) + dsigma=dsigmas[0]; + else + dsigma=dsigmas[myrank]; + + + + + if(useall) + { + // go with every atom in the system but not the virtuals... + if(trimer) + natoms= 2*getTotAtoms()/3; + else + natoms=getTotAtoms()/2; + + for(unsigned int i=0; i<((unsigned int)natoms); i++) + { + AtomNumber ati; + ati.setIndex(i); + atoms.push_back(ati); + } + } + else // serials for the first beads of each dimer are given + { + parseVector("ATOMS",usedatoms); + double ntm; + parse("NATOMS",ntm); + natoms=ntm; + + int isz = usedatoms.size(); + + for(unsigned int i=0; i<isz; i++) + { + AtomNumber ati; + ati.setIndex(usedatoms[i]-1); + atoms.push_back(ati); + + } + + for(unsigned int i=0; i<isz; i++) + { + AtomNumber atip2; + atip2.setIndex(usedatoms[i]+natoms-1); + if(usedatoms[i]>natoms) + error("The Dimer CV requires that when choosing atoms you refere only to the first beads."); + atoms.push_back(atip2); + } + + } + consistencyCheck(); + checkRead(); + beta = 1./(kBoltzmann*temperature); + + addValueWithDerivatives(); // allocate + + requestAtoms(atoms); + + setNotPeriodic(); + } void Dimer::calculate() { - double cv_val=0; - Tensor virial; - vector<Vector> derivatives; - vector<Vector> my_pos=getPositions(); - int atms = my_pos.size(); - vector<Vector> der_b2; - for(int i=0;i<atms/2;i++) - { - Vector dist; - dist = pbcDistance(my_pos[i],my_pos[i+atms/2]); - double distquad=0; - for(int j=0;j<3;j++) - distquad += dist[j]*dist[j]; - - double dsigquad = dsigma*dsigma; - double fac1 = 1.0 + distquad/(2*qexp*dsigquad); - double fac1qm1 = pow(fac1,qexp-1); - - - cv_val += (fac1*fac1qm1-1.0)/beta; - Vector der_val; - Vector mder_val; - for(int j=0;j<3;j++) - { - der_val[j] = -fac1qm1*dist[j]/(dsigquad*beta); - mder_val[j]=-der_val[j]; - } - derivatives.push_back(der_val); - der_b2.push_back(mder_val); - - // virial part: each dimer contributes -x_{ij}*ds/dx_{ij} (s is the CV) - double dfunc = fac1qm1/(beta*dsigquad); - Vector dd(dfunc*dist); - Tensor vv(dd,dist); - virial -= vv; - - } - - derivatives.insert(derivatives.end(), der_b2.begin(), der_b2.end()); - - for(unsigned int i=0;i<derivatives.size();i++) - setAtomsDerivatives(i,derivatives[i]); - - setValue(cv_val); - setBoxDerivatives(virial); - + double cv_val=0; + Tensor virial; + vector<Vector> derivatives; + vector<Vector> my_pos=getPositions(); + int atms = my_pos.size(); + vector<Vector> der_b2; + for(int i=0; i<atms/2; i++) + { + Vector dist; + dist = pbcDistance(my_pos[i],my_pos[i+atms/2]); + double distquad=0; + for(int j=0; j<3; j++) + distquad += dist[j]*dist[j]; + + double dsigquad = dsigma*dsigma; + double fac1 = 1.0 + distquad/(2*qexp*dsigquad); + double fac1qm1 = pow(fac1,qexp-1); + + + cv_val += (fac1*fac1qm1-1.0)/beta; + Vector der_val; + Vector mder_val; + for(int j=0; j<3; j++) + { + der_val[j] = -fac1qm1*dist[j]/(dsigquad*beta); + mder_val[j]=-der_val[j]; + } + derivatives.push_back(der_val); + der_b2.push_back(mder_val); + + // virial part: each dimer contributes -x_{ij}*ds/dx_{ij} (s is the CV) + double dfunc = fac1qm1/(beta*dsigquad); + Vector dd(dfunc*dist); + Tensor vv(dd,dist); + virial -= vv; + + } + + derivatives.insert(derivatives.end(), der_b2.begin(), der_b2.end()); + + for(unsigned int i=0; i<derivatives.size(); i++) + setAtomsDerivatives(i,derivatives[i]); + + setValue(cv_val); + setBoxDerivatives(virial); + } @@ -302,23 +302,24 @@ These are checked here and PLUMED error handlers are (eventually) called. ******************/ void Dimer::consistencyCheck() { - if(useall==false && natoms==0) - error("Either NATOMS or ATOMS are required to specify the number of dimerized atoms."); - - if(qexp<0.5 || qexp>1) - warning("Dimer CV is meant to be used with q-exponents between 0.5 and 1. We are not responsible for any black hole. :-)"); - if(dsigma<0) - error("Please use positive sigma values for the Dimer strength constant"); - if(temperature<0) - error("Please, use a positive value for the temperature..."); - - // if dsigmas has only one element means that either - // you are using different plumed.x.dat files or a plumed.dat with a single replica - if(dsigmas.size()!=nranks && dsigmas.size()!=1) - error("Mismatch between provided sigmas and number of replicas"); + if(useall==false && natoms==0) + error("Either NATOMS or ATOMS are required to specify the number of dimerized atoms."); + + if(qexp<0.5 || qexp>1) + warning("Dimer CV is meant to be used with q-exponents between 0.5 and 1. We are not responsible for any black hole. :-)"); + if(dsigma<0) + error("Please use positive sigma values for the Dimer strength constant"); + if(temperature<0) + error("Please, use a positive value for the temperature..."); + + // if dsigmas has only one element means that either + // you are using different plumed.x.dat files or a plumed.dat with a single replica + if(dsigmas.size()!=nranks && dsigmas.size()!=1) + error("Mismatch between provided sigmas and number of replicas"); } -}} +} +} diff --git a/src/colvar/Dipole.cpp b/src/colvar/Dipole.cpp index 4f0bed030..09a4a6580 100644 --- a/src/colvar/Dipole.cpp +++ b/src/colvar/Dipole.cpp @@ -27,10 +27,10 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { -//+PLUMEDOC COLVAR DIPOLE +//+PLUMEDOC COLVAR DIPOLE /* Calculate the dipole moment for a group of atoms. @@ -43,7 +43,7 @@ PRINT FILE=output STRIDE=5 ARG=5 \endverbatim (see also \ref PRINT) -\attention +\attention If the total charge Q of the group in non zero, then a charge Q/N will be subtracted to every atom, where N is the number of atoms. This implies that the dipole (which for a charged system depends on the position) is computed on the geometric center of the group. @@ -51,7 +51,7 @@ on the position) is computed on the geometric center of the group. */ //+ENDPLUMEDOC - + class Dipole : public Colvar { vector<AtomNumber> ga_lista; bool components; @@ -63,7 +63,7 @@ public: PLUMED_REGISTER_ACTION(Dipole,"DIPOLE") -void Dipole::registerKeywords(Keywords& keys){ +void Dipole::registerKeywords(Keywords& keys) { Colvar::registerKeywords(keys); keys.add("atoms","GROUP","the group of atoms we are calculating the dipole moment for"); keys.addFlag("COMPONENTS",false,"calculate the x, y and z components of the dipole separately and store them as label.x, label.y and label.z"); @@ -74,13 +74,13 @@ void Dipole::registerKeywords(Keywords& keys){ } Dipole::Dipole(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao), -components(false) + PLUMED_COLVAR_INIT(ao), + components(false) { parseAtomList("GROUP",ga_lista); parseFlag("COMPONENTS",components); checkRead(); - if(components){ + if(components) { addComponentWithDerivatives("x"); componentIsNotPeriodic("x"); addComponentWithDerivatives("y"); componentIsNotPeriodic("y"); addComponentWithDerivatives("z"); componentIsNotPeriodic("z"); @@ -89,7 +89,7 @@ components(false) } log.printf(" of %u atoms\n",static_cast<unsigned>(ga_lista.size())); - for(unsigned int i=0;i<ga_lista.size();++i){ + for(unsigned int i=0; i<ga_lista.size(); ++i) { log.printf(" %d", ga_lista[i].serial()); } log.printf(" \n"); @@ -99,48 +99,48 @@ components(false) // calculator void Dipole::calculate() { - double ctot=0.; - unsigned N=getNumberOfAtoms(); - vector<double> charges(N); - Vector dipje; - - for(unsigned i=0;i<N;++i){ - charges[i]=getCharge(i); - ctot+=charges[i]; - } - ctot/=(double)N; - - for(unsigned i=0;i<N;++i) { - charges[i]-=ctot; - dipje += charges[i]*getPosition(i); - } - - if(!components){ - double dipole = dipje.modulo(); - double idip = 1./dipole; - - for(unsigned i=0;i<N;i++) { - double dfunc=charges[i]*idip; - setAtomsDerivatives(i,dfunc*dipje); - } - setBoxDerivativesNoPbc(); - setValue(dipole); - } else { - Value* valuex=getPntrToComponent("x"); - Value* valuey=getPntrToComponent("y"); - Value* valuez=getPntrToComponent("z"); - for(unsigned i=0;i<N;i++) { - setAtomsDerivatives(valuex,i,charges[i]*Vector(1.0,0.0,0.0)); - setAtomsDerivatives(valuey,i,charges[i]*Vector(0.0,1.0,0.0)); - setAtomsDerivatives(valuez,i,charges[i]*Vector(0.0,0.0,1.0)); - } - setBoxDerivativesNoPbc(valuex); - setBoxDerivativesNoPbc(valuey); - setBoxDerivativesNoPbc(valuez); - valuex->set(dipje[0]); - valuey->set(dipje[1]); - valuez->set(dipje[2]); - } + double ctot=0.; + unsigned N=getNumberOfAtoms(); + vector<double> charges(N); + Vector dipje; + + for(unsigned i=0; i<N; ++i) { + charges[i]=getCharge(i); + ctot+=charges[i]; + } + ctot/=(double)N; + + for(unsigned i=0; i<N; ++i) { + charges[i]-=ctot; + dipje += charges[i]*getPosition(i); + } + + if(!components) { + double dipole = dipje.modulo(); + double idip = 1./dipole; + + for(unsigned i=0; i<N; i++) { + double dfunc=charges[i]*idip; + setAtomsDerivatives(i,dfunc*dipje); + } + setBoxDerivativesNoPbc(); + setValue(dipole); + } else { + Value* valuex=getPntrToComponent("x"); + Value* valuey=getPntrToComponent("y"); + Value* valuez=getPntrToComponent("z"); + for(unsigned i=0; i<N; i++) { + setAtomsDerivatives(valuex,i,charges[i]*Vector(1.0,0.0,0.0)); + setAtomsDerivatives(valuey,i,charges[i]*Vector(0.0,1.0,0.0)); + setAtomsDerivatives(valuez,i,charges[i]*Vector(0.0,0.0,1.0)); + } + setBoxDerivativesNoPbc(valuex); + setBoxDerivativesNoPbc(valuey); + setBoxDerivativesNoPbc(valuez); + valuex->set(dipje[0]); + valuey->set(dipje[1]); + valuez->set(dipje[2]); + } } } diff --git a/src/colvar/Distance.cpp b/src/colvar/Distance.cpp index 8ef7c0805..c3a981771 100644 --- a/src/colvar/Distance.cpp +++ b/src/colvar/Distance.cpp @@ -28,8 +28,8 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { //+PLUMEDOC COLVAR DISTANCE /* @@ -110,7 +110,7 @@ with domain (-0.5,+0.5). */ //+ENDPLUMEDOC - + class Distance : public Colvar { bool components; bool scaled_components; @@ -125,11 +125,11 @@ public: PLUMED_REGISTER_ACTION(Distance,"DISTANCE") -void Distance::registerKeywords( Keywords& keys ){ +void Distance::registerKeywords( Keywords& keys ) { Colvar::registerKeywords( keys ); keys.add("atoms","ATOMS","the pair of atom that we are calculating the distance between"); - keys.addFlag("COMPONENTS",false,"calculate the x, y and z components of the distance separately and store them as label.x, label.y and label.z"); - keys.addFlag("SCALED_COMPONENTS",false,"calculate the a, b and c scaled components of the distance separately and store them as label.a, label.b and label.c"); + keys.addFlag("COMPONENTS",false,"calculate the x, y and z components of the distance separately and store them as label.x, label.y and label.z"); + keys.addFlag("SCALED_COMPONENTS",false,"calculate the a, b and c scaled components of the distance separately and store them as label.a, label.b and label.c"); keys.addOutputComponent("x","COMPONENTS","the x-component of the vector connecting the two atoms"); keys.addOutputComponent("y","COMPONENTS","the y-component of the vector connecting the two atoms"); keys.addOutputComponent("z","COMPONENTS","the z-component of the vector connecting the two atoms"); @@ -139,10 +139,10 @@ void Distance::registerKeywords( Keywords& keys ){ } Distance::Distance(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao), -components(false), -scaled_components(false), -pbc(true) + PLUMED_COLVAR_INIT(ao), + components(false), + scaled_components(false), + pbc(true) { vector<AtomNumber> atoms; parseAtomList("ATOMS",atoms); @@ -161,12 +161,12 @@ pbc(true) if(components && scaled_components) error("COMPONENTS and SCALED_COMPONENTS are not compatible"); - if(components){ + if(components) { addComponentWithDerivatives("x"); componentIsNotPeriodic("x"); addComponentWithDerivatives("y"); componentIsNotPeriodic("y"); addComponentWithDerivatives("z"); componentIsNotPeriodic("z"); log<<" WARNING: components will not have the proper periodicity - see manual\n"; - } else if(scaled_components){ + } else if(scaled_components) { addComponentWithDerivatives("a"); componentIsPeriodic("a","-0.5","+0.5"); addComponentWithDerivatives("b"); componentIsPeriodic("b","-0.5","+0.5"); addComponentWithDerivatives("c"); componentIsPeriodic("c","-0.5","+0.5"); @@ -180,7 +180,7 @@ pbc(true) // calculator -void Distance::calculate(){ +void Distance::calculate() { if(pbc) makeWhole(); @@ -188,7 +188,7 @@ void Distance::calculate(){ const double value=distance.modulo(); const double invvalue=1.0/value; - if(components){ + if(components) { Value* valuex=getPntrToComponent("x"); Value* valuey=getPntrToComponent("y"); Value* valuez=getPntrToComponent("z"); @@ -207,7 +207,7 @@ void Distance::calculate(){ setAtomsDerivatives (valuez,1,Vector(0,0,+1)); setBoxDerivativesNoPbc(valuez); valuez->set(distance[2]); - } else if(scaled_components){ + } else if(scaled_components) { Value* valuea=getPntrToComponent("a"); Value* valueb=getPntrToComponent("b"); Value* valuec=getPntrToComponent("c"); diff --git a/src/colvar/ERMSD.cpp b/src/colvar/ERMSD.cpp index 29ce5de51..3602df086 100644 --- a/src/colvar/ERMSD.cpp +++ b/src/colvar/ERMSD.cpp @@ -35,35 +35,35 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { //+PLUMEDOC COLVAR ERMSD /* -Calculate eRMSD with respect to a reference structure. +Calculate eRMSD with respect to a reference structure. -eRMSD is a metric developed for measuring distances between three-dimensional RNA structures. -The standard RMSD measure is highly inaccurate when measuring distances among three-dimensional -structures of nucleic acids. -It is not unusual, for example, that two RNA structures with low RMSD (i.e. less than 0.4nm) display a completely different network of base-base interactions. +eRMSD is a metric developed for measuring distances between three-dimensional RNA structures. +The standard RMSD measure is highly inaccurate when measuring distances among three-dimensional +structures of nucleic acids. +It is not unusual, for example, that two RNA structures with low RMSD (i.e. less than 0.4nm) display a completely different network of base-base interactions. eRMSD measures the distance between structures by considering only the relative positions and orientations of nucleobases. The eRMSD can be considered as a vectorial version of contact maps and it is calculated as follows: -1. Set up a local reference system in the center of the six-membered ring of each nucleobase in a molecule. - The xy plane lies on the plane of the nucleobase, and it is oriented such that the Watson-Crick interaction is always at \f$ \theta \approx 60^{\circ} \f$. +1. Set up a local reference system in the center of the six-membered ring of each nucleobase in a molecule. + The xy plane lies on the plane of the nucleobase, and it is oriented such that the Watson-Crick interaction is always at \f$ \theta \approx 60^{\circ} \f$. -2. Calculate all pairwise distance vectors \f$ \vec{r}_{i,j} \f$ among base centers. +2. Calculate all pairwise distance vectors \f$ \vec{r}_{i,j} \f$ among base centers. 3. Rescale distance vectors as \f$ \tilde{\vec{r}}_{i,j} = (r_x/a,r_y/a,r_z/b) \f$, where \f$ a=b=5 \AA, c= 3 \AA\f$. This rescaling has the effect of weghting more deviations on the z-axis with respect to the x/y directions. -4. Calculate the G vectors +4. Calculate the G vectors \f[ \vec{G}(\tilde{\vec{r}}) = (\sin(\gamma \tilde{r}) \tilde{r}_x/\tilde{r},\sin(\gamma \tilde{r}) \tilde{r}_y/\tilde{r},\sin(\gamma \tilde{r}) \tilde{r}_z/\tilde{r}, 1+\cos(\gamma \tilde{r})) \times \Theta(\tilde{r}_{cutoff}-\tilde{r}) \f] -Here, \f$ \gamma = \pi/\tilde{r}_{cutoff}\f$ and \f$ \Theta \f$ is the Heaviside step function. The default cutoff is set to 2.4. +Here, \f$ \gamma = \pi/\tilde{r}_{cutoff}\f$ and \f$ \Theta \f$ is the Heaviside step function. The default cutoff is set to 2.4. 5. The eRMSD between two structures \f$ \alpha \f$ and \f$ \beta \f$ reads @@ -81,7 +81,7 @@ for a multi molecular system. \par Examples -Calculate the eRMSD from reference structure reference.pdb using the default cutoff (2.4). The list of residues involved in the calculation has to be specified. In this example, the eRMSD is calculated +Calculate the eRMSD from reference structure reference.pdb using the default cutoff (2.4). The list of residues involved in the calculation has to be specified. In this example, the eRMSD is calculated considering residues 1,2,3,4,5,6. \verbatim @@ -91,13 +91,13 @@ eRMSD1: ERMSD REFERENCE=reference.pdb ATOMS=@lcs-1,@lcs-2,@lcs-3,@lcs-4,@lcs-5,@ */ //+ENDPLUMEDOC - + class ERMSD : public Colvar { - - vector<Vector> derivs; - PLMD::ERMSD ermsd; - bool pbc; + + vector<Vector> derivs; + PLMD::ERMSD ermsd; + bool pbc; public: explicit ERMSD(const ActionOptions&); @@ -107,7 +107,7 @@ public: PLUMED_REGISTER_ACTION(ERMSD,"ERMSD") -void ERMSD::registerKeywords(Keywords& keys){ +void ERMSD::registerKeywords(Keywords& keys) { Colvar::registerKeywords(keys); keys.add("compulsory","REFERENCE","a file in pdb format containing the reference structure and the atoms involved in the CV."); @@ -118,7 +118,7 @@ void ERMSD::registerKeywords(Keywords& keys){ } ERMSD::ERMSD(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao), pbc(true) + PLUMED_COLVAR_INIT(ao), pbc(true) { string reference; parse("REFERENCE",reference); @@ -137,13 +137,13 @@ PLUMED_COLVAR_INIT(ao), pbc(true) parseVector("PAIRS",pairs_); checkRead(); - addValueWithDerivatives(); setNotPeriodic(); + addValueWithDerivatives(); setNotPeriodic(); if(atoms_.size()<6) error("at least six atoms should be specified"); if(atoms_.size()%3!=0) error("Atoms are not multiple of 3"); if(pairs_.size()%2!=0) error("pairs are not multiple of 2"); - + //checkRead(); //log.printf(" of atoms"); //for(unsigned i=0;i<atoms.size();++i) log.printf(" %d",atoms[i].serial()); @@ -152,20 +152,20 @@ PLUMED_COLVAR_INIT(ao), pbc(true) // read everything in ang and transform to nm if we are not in natural units PDB pdb; if( !pdb.read(reference,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength()) ) - error("missing input file " + reference ); + error("missing input file " + reference ); // store target_ distance vector <Vector> reference_positions; unsigned natoms = atoms_.size(); log.printf("Read %u atoms\n",natoms); reference_positions.resize(natoms); - for(unsigned i=0;i<natoms;i++){ - reference_positions[i] = pdb.getPosition(atoms_[i]); - //log.printf("%f %f %f \n",reference_positions[i][0],reference_positions[i][1],reference_positions[i][2]); + for(unsigned i=0; i<natoms; i++) { + reference_positions[i] = pdb.getPosition(atoms_[i]); + //log.printf("%f %f %f \n",reference_positions[i][0],reference_positions[i][1],reference_positions[i][2]); } // shift to count from zero - for(unsigned i=0;i<pairs_.size();++i) pairs_[i]--; + for(unsigned i=0; i<pairs_.size(); ++i) pairs_[i]--; ermsd.setReference(reference_positions,pairs_,cutoff); @@ -178,32 +178,32 @@ PLUMED_COLVAR_INIT(ao), pbc(true) log<<" Bibliography " <<plumed.cite("Bottaro, Di Palma, and Bussi, Nucleic Acids Res. 42, 13306 (2014)") <<plumed.cite("Bottaro, Banas, Sponer, and Bussi, submitted (2016)")<<"\n"; - + } // calculator -void ERMSD::calculate(){ +void ERMSD::calculate() { // set derivatives to zero - for(unsigned i=0;i<derivs.size();++i) {derivs[i].zero();} - double ermsdist; - Tensor virial; + for(unsigned i=0; i<derivs.size(); ++i) {derivs[i].zero();} + double ermsdist; + Tensor virial; // This is a trick to avoid explicit virial calculation // 1. we make the molecule whole - makeWhole(); + makeWhole(); // 2. we ignore pbcs - Pbc fake_pbc; + Pbc fake_pbc; // Notice that this might have problems when having 2 RNA molecules (hybridization). - ermsdist=ermsd.calculate(getPositions(),fake_pbc,derivs,virial); - setValue(ermsdist); + ermsdist=ermsd.calculate(getPositions(),fake_pbc,derivs,virial); + setValue(ermsdist); + + for(unsigned i=0; i<derivs.size(); ++i) {setAtomsDerivatives(i,derivs[i]);} - for(unsigned i=0;i<derivs.size();++i) {setAtomsDerivatives(i,derivs[i]);} - - setBoxDerivativesNoPbc(); + setBoxDerivativesNoPbc(); - //setBoxDerivatives(virial); +//setBoxDerivatives(virial); - } +} } } diff --git a/src/colvar/Energy.cpp b/src/colvar/Energy.cpp index f8d8f7b12..11e2532e0 100644 --- a/src/colvar/Energy.cpp +++ b/src/colvar/Energy.cpp @@ -27,8 +27,8 @@ #include <string> #include <cmath> -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { //+PLUMEDOC COLVAR ENERGY /* @@ -42,7 +42,7 @@ metadynamics applied to ENERGY can be used to decrease the number of required replicas. \bug Acceptance for replica exchange when \ref ENERGY is biased -is computed correctly only of all the replicas has the same +is computed correctly only of all the replicas has the same potential energy function. This is for instance not true when using GROMACS with lambda replica exchange of with plumed-hrex branch. @@ -76,7 +76,7 @@ using namespace std; PLUMED_REGISTER_ACTION(Energy,"ENERGY") Energy::Energy(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao) + PLUMED_COLVAR_INIT(ao) { // if(checkNumericalDerivatives()) // error("Cannot use NUMERICAL_DERIVATIVES with ENERGY"); @@ -89,23 +89,23 @@ PLUMED_COLVAR_INIT(ao) log<<"\n"; } -void Energy::registerKeywords( Keywords& keys ){ +void Energy::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionAtomistic::registerKeywords( keys ); ActionWithValue::registerKeywords( keys ); - keys.remove("NUMERICAL_DERIVATIVES"); + keys.remove("NUMERICAL_DERIVATIVES"); } -unsigned Energy::getNumberOfDerivatives(){ +unsigned Energy::getNumberOfDerivatives() { return 1; } -void Energy::prepare(){ +void Energy::prepare() { plumed.getAtoms().setCollectEnergy(true); } // calculator -void Energy::calculate(){ +void Energy::calculate() { setValue( getEnergy() ); getPntrToComponent(0)->addDerivative(0,1.0); } diff --git a/src/colvar/Fake.cpp b/src/colvar/Fake.cpp index 4a28cbf38..70bd7f278 100644 --- a/src/colvar/Fake.cpp +++ b/src/colvar/Fake.cpp @@ -29,10 +29,10 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { -//+PLUMEDOC COLVAR FAKE +//+PLUMEDOC COLVAR FAKE /* This is a fake colvar container used by cltools or various other actions and just support input and period definition @@ -46,7 +46,7 @@ FAKE ATOMS=1 PERIODIC=-3.14,3.14 LABEL=d2 */ //+ENDPLUMEDOC - + class ColvarFake : public Colvar { public: @@ -58,7 +58,7 @@ public: PLUMED_REGISTER_ACTION(ColvarFake,"FAKE") -void ColvarFake::registerKeywords( Keywords& keys ){ +void ColvarFake::registerKeywords( Keywords& keys ) { Colvar::registerKeywords( keys ); keys.add("atoms","ATOMS","the fake atom index, a number is enough"); keys.reserve("compulsory","PERIODIC","if the output of your function is periodic then you should specify the periodicity of the function. If the output is not periodic you must state this using PERIODIC=NO,NO (one for the lower and the other for the upper boundary). For multicomponents then it is PERIODIC=mincomp1,maxcomp1,mincomp2,maxcomp2 etc "); @@ -67,61 +67,61 @@ void ColvarFake::registerKeywords( Keywords& keys ){ } ColvarFake::ColvarFake(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao) + PLUMED_COLVAR_INIT(ao) { vector<AtomNumber> atoms; parseAtomList("ATOMS",atoms); - vector<string> comps; - // multiple components for this variable + vector<string> comps; + // multiple components for this variable parseVector("COMPONENTS",comps); - if(comps.size()!=0){ - for(unsigned i=0;i<comps.size();i++){ - addComponentWithDerivatives(comps[i]); - } - // periodicity - }else{ - // only one component for this variable - addValueWithDerivatives(); + if(comps.size()!=0) { + for(unsigned i=0; i<comps.size(); i++) { + addComponentWithDerivatives(comps[i]); + } + // periodicity + } else { + // only one component for this variable + addValueWithDerivatives(); } std::vector<std::string> period; parseVector("PERIODIC",period); - if(period.size()!=0){ - plumed_massert(getNumberOfComponents()*2==period.size(),"the periodicty should coincide with the number of components"); - if(comps.size()!=0){ - for(int i=0;i<getNumberOfComponents();i++){ - string pp=comps[i]; - if(period[i*2]!="none" && period[i*2+1]!="none" ){ - componentIsPeriodic(pp,period[i*2],period[i*2+1]); - }else{ - componentIsNotPeriodic(pp); - } - } - }else{ - if(period[0]!="none" && period[1]!="none" ){ - setPeriodic(period[0],period[1]); - }else{ - setNotPeriodic(); - } - } - }else{ - if(comps.size()!=0){ - for(int i=0;i<getNumberOfComponents();i++){ - componentIsNotPeriodic(getPntrToComponent(i)->getName()); - } - } else { - setNotPeriodic(); - } + if(period.size()!=0) { + plumed_massert(getNumberOfComponents()*2==period.size(),"the periodicty should coincide with the number of components"); + if(comps.size()!=0) { + for(int i=0; i<getNumberOfComponents(); i++) { + string pp=comps[i]; + if(period[i*2]!="none" && period[i*2+1]!="none" ) { + componentIsPeriodic(pp,period[i*2],period[i*2+1]); + } else { + componentIsNotPeriodic(pp); + } + } + } else { + if(period[0]!="none" && period[1]!="none" ) { + setPeriodic(period[0],period[1]); + } else { + setNotPeriodic(); + } + } + } else { + if(comps.size()!=0) { + for(int i=0; i<getNumberOfComponents(); i++) { + componentIsNotPeriodic(getPntrToComponent(i)->getName()); + } + } else { + setNotPeriodic(); + } } - checkRead(); - requestAtoms(atoms); + checkRead(); + requestAtoms(atoms); } // calculator -void ColvarFake::calculate(){ - plumed_merror("you should never have got here"); +void ColvarFake::calculate() { + plumed_merror("you should never have got here"); } } diff --git a/src/colvar/FretEfficiency.cpp b/src/colvar/FretEfficiency.cpp index 9840c749d..02600e105 100644 --- a/src/colvar/FretEfficiency.cpp +++ b/src/colvar/FretEfficiency.cpp @@ -28,8 +28,8 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { //+PLUMEDOC COLVAR FRET /* @@ -48,7 +48,7 @@ boundary conditions. This behavior can be changed with the NOPBC flag. \par Examples -The following input tells plumed to print the FRET efficiencies +The following input tells plumed to print the FRET efficiencies calculated as a function of the distance between atoms 3 and 5 and the distance between atoms 2 and 4. \verbatim @@ -73,7 +73,7 @@ to be sure that if the distance is larger than half the simulation box the distance is compute properly. Also notice that, since many MD codes break molecules across cell boundary, it might be necessary to use the \ref WHOLEMOLECULES keyword (also notice that it should be -_before_ FRET). +_before_ FRET). Just be sure that the ordered list provide to WHOLEMOLECULES has the following properties: - Consecutive atoms should be closer than half-cell throughout the entire simulation. @@ -81,7 +81,7 @@ properties: */ //+ENDPLUMEDOC - + class FretEfficiency : public Colvar { bool pbc; double R0_; @@ -95,21 +95,21 @@ public: PLUMED_REGISTER_ACTION(FretEfficiency,"FRET") -void FretEfficiency::registerKeywords( Keywords& keys ){ +void FretEfficiency::registerKeywords( Keywords& keys ) { Colvar::registerKeywords( keys ); keys.add("atoms","ATOMS","the pair of atom that we are calculating the distance between"); keys.add("compulsory","R0","The value of the Forster radius."); } FretEfficiency::FretEfficiency(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao), -pbc(true) + PLUMED_COLVAR_INIT(ao), + pbc(true) { vector<AtomNumber> atoms; parseAtomList("ATOMS",atoms); if(atoms.size()!=2) error("Number of specified atoms should be 2"); - parse("R0",R0_); + parse("R0",R0_); bool nopbc=!pbc; parseFlag("NOPBC",nopbc); pbc=!nopbc; @@ -129,14 +129,14 @@ pbc(true) // calculator -void FretEfficiency::calculate(){ +void FretEfficiency::calculate() { if(pbc) makeWhole(); Vector distance=delta(getPosition(0),getPosition(1)); const double dist_mod=distance.modulo(); const double inv_dist_mod=1.0/dist_mod; - + const double ratiosix=pow(dist_mod/R0_,6); const double fret_eff = 1.0/(1.0+ratiosix); diff --git a/src/colvar/Gyration.cpp b/src/colvar/Gyration.cpp index 9471593e9..5cf35aea0 100644 --- a/src/colvar/Gyration.cpp +++ b/src/colvar/Gyration.cpp @@ -29,26 +29,26 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { //+PLUMEDOC COLVAR GYRATION /* Calculate the radius of gyration, or other properties related to it. The different properties can be calculated and selected by the TYPE keyword: -the Radius of Gyration (RADIUS); the Trace of the Gyration Tensor (TRACE); +the Radius of Gyration (RADIUS); the Trace of the Gyration Tensor (TRACE); the Largest Principal Moment of the Gyration Tensor (GTPC_1); the middle Principal Moment of the Gyration Tensor (GTPC_2); the Smallest Principal Moment of the Gyration Tensor (GTPC_3); the Asphericiry (ASPHERICITY); the Acylindricity (ACYLINDRICITY); -the Relative Shape Anisotropy (KAPPA2); the Smallest Principal Radius Of Gyration (GYRATION_3); +the Relative Shape Anisotropy (KAPPA2); the Smallest Principal Radius Of Gyration (GYRATION_3); the Middle Principal Radius of Gyration (GYRATION_2); the Largest Principal Radius of Gyration (GYRATION_1). A derivation of all these different variants can be found in \cite Vymetal:2011gv The radius of gyration is calculated using: \f[ -s_{\rm Gyr}=\Big ( \frac{\sum_i^{n} - m_i \vert {r}_i -{r}_{\rm COM} \vert ^2 }{\sum_i^{n} m_i} \Big)^{1/2} +s_{\rm Gyr}=\Big ( \frac{\sum_i^{n} + m_i \vert {r}_i -{r}_{\rm COM} \vert ^2 }{\sum_i^{n} m_i} \Big)^{1/2} \f] with the position of the center of mass \f${r}_{\rm COM}\f$ given by: @@ -57,14 +57,14 @@ with the position of the center of mass \f${r}_{\rm COM}\f$ given by: {r}_{\rm COM}=\frac{\sum_i^{n} {r}_i\ m_i }{\sum_i^{n} m_i} \f] -The radius of gyration usually makes sense when atoms used for the calculation +The radius of gyration usually makes sense when atoms used for the calculation are all part of the same molecule. -When running with periodic boundary conditions, the atoms should be +When running with periodic boundary conditions, the atoms should be in the proper periodic image. This is done automatically since PLUMED 2.2, by considering the ordered list of atoms and rebuilding PBCs with a procedure that is equivalent to that done in \ref WHOLEMOLECULES . Notice that rebuilding is local to this action. This is different from \ref WHOLEMOLECULES -which actually modifies the coordinates stored in PLUMED. +which actually modifies the coordinates stored in PLUMED. In case you want to recover the old behavior you should use the NOPBC flag. In that case you need to take care that atoms are in the correct @@ -73,11 +73,11 @@ periodic image. \par Examples -The following input tells plumed to print the radius of gyration of the +The following input tells plumed to print the radius of gyration of the chain containing atoms 10 to 20. \verbatim GYRATION TYPE=RADIUS ATOMS=10-20 LABEL=rg -PRINT ARG=rg STRIDE=1 FILE=colvar +PRINT ARG=rg STRIDE=1 FILE=colvar \endverbatim (See also \ref PRINT) @@ -98,7 +98,7 @@ public: PLUMED_REGISTER_ACTION(Gyration,"GYRATION") -void Gyration::registerKeywords(Keywords& keys){ +void Gyration::registerKeywords(Keywords& keys) { Colvar::registerKeywords(keys); keys.add("atoms","ATOMS","the group of atoms that you are calculating the Gyration Tensor for"); keys.add("compulsory","TYPE","RADIUS","The type of calculation relative to the Gyration Tensor you want to perform"); @@ -106,9 +106,9 @@ void Gyration::registerKeywords(Keywords& keys){ } Gyration::Gyration(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao), -use_masses(false), -nopbc(false) + PLUMED_COLVAR_INIT(ao), + use_masses(false), + nopbc(false) { std::vector<AtomNumber> atoms; parseAtomList("ATOMS",atoms); @@ -134,25 +134,25 @@ nopbc(false) switch(rg_type) { - case RADIUS: log.printf(" GYRATION RADIUS (Rg);"); break; - case TRACE: log.printf(" TRACE OF THE GYRATION TENSOR;"); break; - case GTPC_1: log.printf(" THE LARGEST PRINCIPAL MOMENT OF THE GYRATION TENSOR (S'_1);"); break; - case GTPC_2: log.printf(" THE MIDDLE PRINCIPAL MOMENT OF THE GYRATION TENSOR (S'_2);"); break; - case GTPC_3: log.printf(" THE SMALLEST PRINCIPAL MOMENT OF THE GYRATION TENSOR (S'_3);"); break; - case ASPHERICITY: log.printf(" THE ASPHERICITY (b');"); break; - case ACYLINDRICITY: log.printf(" THE ACYLINDRICITY (c');"); break; - case KAPPA2: log.printf(" THE RELATIVE SHAPE ANISOTROPY (kappa^2);"); break; - case GYRATION_3: log.printf(" THE SMALLEST PRINCIPAL RADIUS OF GYRATION (r_g3);"); break; - case GYRATION_2: log.printf(" THE MIDDLE PRINCIPAL RADIUS OF GYRATION (r_g2);"); break; - case GYRATION_1: log.printf(" THE LARGEST PRINCIPAL RADIUS OF GYRATION (r_g1);"); break; + case RADIUS: log.printf(" GYRATION RADIUS (Rg);"); break; + case TRACE: log.printf(" TRACE OF THE GYRATION TENSOR;"); break; + case GTPC_1: log.printf(" THE LARGEST PRINCIPAL MOMENT OF THE GYRATION TENSOR (S'_1);"); break; + case GTPC_2: log.printf(" THE MIDDLE PRINCIPAL MOMENT OF THE GYRATION TENSOR (S'_2);"); break; + case GTPC_3: log.printf(" THE SMALLEST PRINCIPAL MOMENT OF THE GYRATION TENSOR (S'_3);"); break; + case ASPHERICITY: log.printf(" THE ASPHERICITY (b');"); break; + case ACYLINDRICITY: log.printf(" THE ACYLINDRICITY (c');"); break; + case KAPPA2: log.printf(" THE RELATIVE SHAPE ANISOTROPY (kappa^2);"); break; + case GYRATION_3: log.printf(" THE SMALLEST PRINCIPAL RADIUS OF GYRATION (r_g3);"); break; + case GYRATION_2: log.printf(" THE MIDDLE PRINCIPAL RADIUS OF GYRATION (r_g2);"); break; + case GYRATION_1: log.printf(" THE LARGEST PRINCIPAL RADIUS OF GYRATION (r_g1);"); break; } if(rg_type>TRACE) log<<" Bibliography "<<plumed.cite("JiriÌ Vymetal and JiriÌ Vondrasek, J. Phys. Chem. A 115, 11455 (2011)"); log<<"\n"; log.printf(" atoms involved : "); - for(unsigned i=0;i<atoms.size();++i) log.printf("%d ",atoms[i].serial()); + for(unsigned i=0; i<atoms.size(); ++i) log.printf("%d ",atoms[i].serial()); log.printf("\n"); - if(!nopbc){ + if(!nopbc) { log<<" PBC will be ignored\n"; } else { log<<" broken molecules will be rebuilt assuming atoms are in the proper order\n"; @@ -162,20 +162,20 @@ nopbc(false) requestAtoms(atoms); } -void Gyration::calculate(){ +void Gyration::calculate() { if(!nopbc) makeWhole(); Vector com; - double totmass = 0.; + double totmass = 0.; if( use_masses ) { - for(unsigned i=0;i<getNumberOfAtoms();i++){ + for(unsigned i=0; i<getNumberOfAtoms(); i++) { totmass+=getMass(i); com+=getMass(i)*getPosition(i); } } else { totmass = static_cast<double>(getNumberOfAtoms()); - for(unsigned i=0;i<getNumberOfAtoms();i++){ + for(unsigned i=0; i<getNumberOfAtoms(); i++) { com+=getPosition(i); } } @@ -186,15 +186,15 @@ void Gyration::calculate(){ Tensor virial; if(rg_type==RADIUS||rg_type==TRACE) { - if( use_masses ){ - for(unsigned i=0;i<getNumberOfAtoms();i++){ + if( use_masses ) { + for(unsigned i=0; i<getNumberOfAtoms(); i++) { const Vector diff = delta( com, getPosition(i) ); rgyr += getMass(i)*diff.modulo2(); derivatives[i] = diff*getMass(i); virial -= Tensor(getPosition(i),derivatives[i]); } } else { - for(unsigned i=0;i<getNumberOfAtoms();i++){ + for(unsigned i=0; i<getNumberOfAtoms(); i++) { const Vector diff = delta( com, getPosition(i) ); rgyr += diff.modulo2(); derivatives[i] = diff; @@ -210,17 +210,17 @@ void Gyration::calculate(){ fact = 4; } setValue(rgyr); - for(unsigned i=0;i<getNumberOfAtoms();i++) setAtomsDerivatives(i,fact*derivatives[i]); + for(unsigned i=0; i<getNumberOfAtoms(); i++) setAtomsDerivatives(i,fact*derivatives[i]); setBoxDerivatives(fact*virial); return; } Matrix<double> gyr_tens(3,3); - for(unsigned i=0;i<3;i++) for(unsigned j=0;j<3;j++) gyr_tens(i,j)=0.; + for(unsigned i=0; i<3; i++) for(unsigned j=0; j<3; j++) gyr_tens(i,j)=0.; //calculate gyration tensor if( use_masses ) { - for(unsigned i=0;i<getNumberOfAtoms();i++){ + for(unsigned i=0; i<getNumberOfAtoms(); i++) { const Vector diff=delta( com, getPosition(i) ); gyr_tens[0][0]+=getMass(i)*diff[0]*diff[0]; gyr_tens[1][1]+=getMass(i)*diff[1]*diff[1]; @@ -230,7 +230,7 @@ void Gyration::calculate(){ gyr_tens[1][2]+=getMass(i)*diff[1]*diff[2]; } } else { - for(unsigned i=0;i<getNumberOfAtoms();i++){ + for(unsigned i=0; i<getNumberOfAtoms(); i++) { const Vector diff=delta( com, getPosition(i) ); gyr_tens[0][0]+=diff[0]*diff[0]; gyr_tens[1][1]+=diff[1]*diff[1]; @@ -252,124 +252,124 @@ void Gyration::calculate(){ diagMat(gyr_tens, princ_comp, ttransf); transpose(ttransf, transf); //sort eigenvalues and eigenvectors - if (princ_comp[0]<princ_comp[1]){ + if (princ_comp[0]<princ_comp[1]) { double tmp=princ_comp[0]; princ_comp[0]=princ_comp[1]; princ_comp[1]=tmp; - for (unsigned i=0; i<3; i++){tmp=transf[i][0]; transf[i][0]=transf[i][1]; transf[i][1]=tmp;} + for (unsigned i=0; i<3; i++) {tmp=transf[i][0]; transf[i][0]=transf[i][1]; transf[i][1]=tmp;} } - if (princ_comp[1]<princ_comp[2]){ + if (princ_comp[1]<princ_comp[2]) { double tmp=princ_comp[1]; princ_comp[1]=princ_comp[2]; princ_comp[2]=tmp; - for (unsigned i=0; i<3; i++){tmp=transf[i][1]; transf[i][1]=transf[i][2]; transf[i][2]=tmp;} + for (unsigned i=0; i<3; i++) {tmp=transf[i][1]; transf[i][1]=transf[i][2]; transf[i][2]=tmp;} } - if (princ_comp[0]<princ_comp[1]){ + if (princ_comp[0]<princ_comp[1]) { double tmp=princ_comp[0]; princ_comp[0]=princ_comp[1]; princ_comp[1]=tmp; - for (unsigned i=0; i<3; i++){tmp=transf[i][0]; transf[i][0]=transf[i][1]; transf[i][1]=tmp;} + for (unsigned i=0; i<3; i++) {tmp=transf[i][0]; transf[i][0]=transf[i][1]; transf[i][1]=tmp;} } //calculate determinant of transformation matrix double det = transf[0][0]*transf[1][1]*transf[2][2]+transf[0][1]*transf[1][2]*transf[2][0]+ transf[0][2]*transf[1][0]*transf[2][1]-transf[0][2]*transf[1][1]*transf[2][0]- - transf[0][1]*transf[1][0]*transf[2][2]-transf[0][0]*transf[1][2]*transf[2][1]; + transf[0][1]*transf[1][0]*transf[2][2]-transf[0][0]*transf[1][2]*transf[2][1]; // trasformation matrix for rotation must have positive determinant, otherwise multiply one column by (-1) - if(det<0) { - for(unsigned j=0;j<3;j++) transf[j][2]=-transf[j][2]; + if(det<0) { + for(unsigned j=0; j<3; j++) transf[j][2]=-transf[j][2]; det = -det; - } + } if(fabs(det-1.)>0.0001) error("Plumed Error: Cannot diagonalize gyration tensor\n"); switch(rg_type) { - case GTPC_1: - case GTPC_2: - case GTPC_3: - { - int pc_index = rg_type-2; //index of principal component - rgyr=sqrt(princ_comp[pc_index]/totmass); - double rm = rgyr*totmass; - if(rm>1e-6) prefactor[pc_index]=1.0/rm; //some parts of derivate - break; - } - case GYRATION_3: //the smallest principal radius of gyration - { - rgyr=sqrt((princ_comp[1]+princ_comp[2])/totmass); - double rm = rgyr*totmass; - if (rm>1e-6){ - prefactor[1]=1.0/rm; - prefactor[2]=1.0/rm; - } - break; + case GTPC_1: + case GTPC_2: + case GTPC_3: + { + int pc_index = rg_type-2; //index of principal component + rgyr=sqrt(princ_comp[pc_index]/totmass); + double rm = rgyr*totmass; + if(rm>1e-6) prefactor[pc_index]=1.0/rm; //some parts of derivate + break; + } + case GYRATION_3: //the smallest principal radius of gyration + { + rgyr=sqrt((princ_comp[1]+princ_comp[2])/totmass); + double rm = rgyr*totmass; + if (rm>1e-6) { + prefactor[1]=1.0/rm; + prefactor[2]=1.0/rm; } - case GYRATION_2: //the midle principal radius of gyration - { - rgyr=sqrt((princ_comp[0]+princ_comp[2])/totmass); - double rm = rgyr*totmass; - if (rm>1e-6){ - prefactor[0]=1.0/rm; - prefactor[2]=1.0/rm; - } - break; + break; + } + case GYRATION_2: //the midle principal radius of gyration + { + rgyr=sqrt((princ_comp[0]+princ_comp[2])/totmass); + double rm = rgyr*totmass; + if (rm>1e-6) { + prefactor[0]=1.0/rm; + prefactor[2]=1.0/rm; } - case GYRATION_1: //the largest principal radius of gyration - { - rgyr=sqrt((princ_comp[0]+princ_comp[1])/totmass); - double rm = rgyr*totmass; - if (rm>1e-6){ - prefactor[0]=1.0/rm; - prefactor[1]=1.0/rm; - } - break; + break; + } + case GYRATION_1: //the largest principal radius of gyration + { + rgyr=sqrt((princ_comp[0]+princ_comp[1])/totmass); + double rm = rgyr*totmass; + if (rm>1e-6) { + prefactor[0]=1.0/rm; + prefactor[1]=1.0/rm; } - case ASPHERICITY: - { - rgyr=sqrt((princ_comp[0]-0.5*(princ_comp[1]+princ_comp[2]))/totmass); - double rm = rgyr*totmass; - if (rm>1e-6){ - prefactor[0]= 1.0/rm; - prefactor[1]=-0.5/rm; - prefactor[2]=-0.5/rm; - } - break; + break; + } + case ASPHERICITY: + { + rgyr=sqrt((princ_comp[0]-0.5*(princ_comp[1]+princ_comp[2]))/totmass); + double rm = rgyr*totmass; + if (rm>1e-6) { + prefactor[0]= 1.0/rm; + prefactor[1]=-0.5/rm; + prefactor[2]=-0.5/rm; } - case ACYLINDRICITY: - { - rgyr=sqrt((princ_comp[1]-princ_comp[2])/totmass); - double rm = rgyr*totmass; - if (rm>1e-6){ //avoid division by zero - prefactor[1]= 1.0/rm; - prefactor[2]=-1.0/rm; - } - break; + break; + } + case ACYLINDRICITY: + { + rgyr=sqrt((princ_comp[1]-princ_comp[2])/totmass); + double rm = rgyr*totmass; + if (rm>1e-6) { //avoid division by zero + prefactor[1]= 1.0/rm; + prefactor[2]=-1.0/rm; } - case KAPPA2: // relative shape anisotropy - { - double trace = princ_comp[0]+princ_comp[1]+princ_comp[2]; - double tmp=princ_comp[0]*princ_comp[1]+ princ_comp[1]*princ_comp[2]+ princ_comp[0]*princ_comp[2]; - rgyr=1.0-3*(tmp/(trace*trace)); - if (rgyr>1e-6){ - prefactor[0]= -3*((princ_comp[1]+princ_comp[2])-2*tmp/trace)/(trace*trace) *2; - prefactor[1]= -3*((princ_comp[0]+princ_comp[2])-2*tmp/trace)/(trace*trace) *2; - prefactor[2]= -3*((princ_comp[0]+princ_comp[1])-2*tmp/trace)/(trace*trace) *2; - } - break; + break; + } + case KAPPA2: // relative shape anisotropy + { + double trace = princ_comp[0]+princ_comp[1]+princ_comp[2]; + double tmp=princ_comp[0]*princ_comp[1]+ princ_comp[1]*princ_comp[2]+ princ_comp[0]*princ_comp[2]; + rgyr=1.0-3*(tmp/(trace*trace)); + if (rgyr>1e-6) { + prefactor[0]= -3*((princ_comp[1]+princ_comp[2])-2*tmp/trace)/(trace*trace) *2; + prefactor[1]= -3*((princ_comp[0]+princ_comp[2])-2*tmp/trace)/(trace*trace) *2; + prefactor[2]= -3*((princ_comp[0]+princ_comp[1])-2*tmp/trace)/(trace*trace) *2; } + break; + } } - if(use_masses) { - for(unsigned i=0;i<getNumberOfAtoms();i++){ + if(use_masses) { + for(unsigned i=0; i<getNumberOfAtoms(); i++) { Vector tX; const Vector diff=delta( com,getPosition(i) ); //project atomic postional vectors to diagonalized frame - for(unsigned j=0;j<3;j++) tX[j]=transf[0][j]*diff[0]+transf[1][j]*diff[1]+transf[2][j]*diff[2]; - for(unsigned j=0;j<3;j++) derivatives[i][j]=getMass(i)*(prefactor[0]*transf[j][0]*tX[0]+ - prefactor[1]*transf[j][1]*tX[1]+ - prefactor[2]*transf[j][2]*tX[2]); + for(unsigned j=0; j<3; j++) tX[j]=transf[0][j]*diff[0]+transf[1][j]*diff[1]+transf[2][j]*diff[2]; + for(unsigned j=0; j<3; j++) derivatives[i][j]=getMass(i)*(prefactor[0]*transf[j][0]*tX[0]+ + prefactor[1]*transf[j][1]*tX[1]+ + prefactor[2]*transf[j][2]*tX[2]); setAtomsDerivatives(i,derivatives[i]); } } else { - for(unsigned i=0;i<getNumberOfAtoms();i++){ + for(unsigned i=0; i<getNumberOfAtoms(); i++) { Vector tX; const Vector diff=delta( com,getPosition(i) ); //project atomic postional vectors to diagonalized frame - for(unsigned j=0;j<3;j++) tX[j]=transf[0][j]*diff[0]+transf[1][j]*diff[1]+transf[2][j]*diff[2]; - for(unsigned j=0;j<3;j++) derivatives[i][j]=prefactor[0]*transf[j][0]*tX[0]+ - prefactor[1]*transf[j][1]*tX[1]+ - prefactor[2]*transf[j][2]*tX[2]; + for(unsigned j=0; j<3; j++) tX[j]=transf[0][j]*diff[0]+transf[1][j]*diff[1]+transf[2][j]*diff[2]; + for(unsigned j=0; j<3; j++) derivatives[i][j]=prefactor[0]*transf[j][0]*tX[0]+ + prefactor[1]*transf[j][1]*tX[1]+ + prefactor[2]*transf[j][2]*tX[2]; setAtomsDerivatives(i,derivatives[i]); } } diff --git a/src/colvar/Implicit.cpp b/src/colvar/Implicit.cpp index 5f3dc191b..ad53f243c 100644 --- a/src/colvar/Implicit.cpp +++ b/src/colvar/Implicit.cpp @@ -79,1119 +79,1119 @@ PRINT ARG=solv FILE=SOLV //+ENDPLUMEDOC class Implicit : public Colvar { - private: - bool pbc; - double buffer; - double delta_g_ref; - unsigned stride; - unsigned nl_update; - vector<vector<unsigned> > nl; - vector<vector<bool> > nlexpo; - vector<vector<double> > parameter; - void setupConstants(const vector<AtomNumber> &atoms, vector<vector<double> > ¶meter, bool tcorr); - map<string, map<string, string> > setupTypeMap(); - map<string, vector<double> > setupValueMap(); - void update_neighb(); +private: + bool pbc; + double buffer; + double delta_g_ref; + unsigned stride; + unsigned nl_update; + vector<vector<unsigned> > nl; + vector<vector<bool> > nlexpo; + vector<vector<double> > parameter; + void setupConstants(const vector<AtomNumber> &atoms, vector<vector<double> > ¶meter, bool tcorr); + map<string, map<string, string> > setupTypeMap(); + map<string, vector<double> > setupValueMap(); + void update_neighb(); - public: - static void registerKeywords(Keywords& keys); - explicit Implicit(const ActionOptions&); - virtual void calculate(); +public: + static void registerKeywords(Keywords& keys); + explicit Implicit(const ActionOptions&); + virtual void calculate(); }; PLUMED_REGISTER_ACTION(Implicit,"IMPLICIT") void Implicit::registerKeywords(Keywords& keys) { - Colvar::registerKeywords(keys); - componentsAreNotOptional(keys); - useCustomisableComponents(keys); - keys.add("atoms", "ATOMS", "The atoms to be included in the calculation, e.g. the whole protein."); - keys.add("compulsory", "NL_BUFFER", "The buffer to the intrinsic cutoff used when calculating pairwise interactions."); - keys.add("compulsory", "NL_STRIDE", "The frequency with which the neighbourlist is updated."); - keys.addFlag("TEMP_CORRECTION", false, "Correct free energy of solvation constants for temperatures different from 298.15 K"); + Colvar::registerKeywords(keys); + componentsAreNotOptional(keys); + useCustomisableComponents(keys); + keys.add("atoms", "ATOMS", "The atoms to be included in the calculation, e.g. the whole protein."); + keys.add("compulsory", "NL_BUFFER", "The buffer to the intrinsic cutoff used when calculating pairwise interactions."); + keys.add("compulsory", "NL_STRIDE", "The frequency with which the neighbourlist is updated."); + keys.addFlag("TEMP_CORRECTION", false, "Correct free energy of solvation constants for temperatures different from 298.15 K"); } Implicit::Implicit(const ActionOptions&ao): - PLUMED_COLVAR_INIT(ao), - pbc(true), - buffer(0.1), - delta_g_ref(0.), - stride(10), - nl_update(0) + PLUMED_COLVAR_INIT(ao), + pbc(true), + buffer(0.1), + delta_g_ref(0.), + stride(10), + nl_update(0) { - vector<AtomNumber> atoms; - parseAtomList("ATOMS", atoms); - const unsigned size = atoms.size(); - bool tcorr = false; - parseFlag("TEMP_CORRECTION", tcorr); - parse("NL_BUFFER", buffer); - parse("NL_STRIDE", stride); + vector<AtomNumber> atoms; + parseAtomList("ATOMS", atoms); + const unsigned size = atoms.size(); + bool tcorr = false; + parseFlag("TEMP_CORRECTION", tcorr); + parse("NL_BUFFER", buffer); + parse("NL_STRIDE", stride); - bool nopbc = !pbc; - parseFlag("NOPBC", nopbc); - pbc = !nopbc; + bool nopbc = !pbc; + parseFlag("NOPBC", nopbc); + pbc = !nopbc; - checkRead(); + checkRead(); - log << " Bibliography " << plumed.cite("Bottaro S, Lindorff-Larsen K, Best R, J. Chem. Theory Comput. 9, 5641 (2013)") - << plumed.cite("Lazaridis T, Karplus M, Proteins Struct. Funct. Genet. 35, 133 (1999)"); log << "\n"; + log << " Bibliography " << plumed.cite("Bottaro S, Lindorff-Larsen K, Best R, J. Chem. Theory Comput. 9, 5641 (2013)") + << plumed.cite("Lazaridis T, Karplus M, Proteins Struct. Funct. Genet. 35, 133 (1999)"); log << "\n"; - nl.resize(size); - nlexpo.resize(size); - parameter.resize(size, vector<double>(4, 0)); - setupConstants(atoms, parameter, tcorr); + nl.resize(size); + nlexpo.resize(size); + parameter.resize(size, vector<double>(4, 0)); + setupConstants(atoms, parameter, tcorr); - addValueWithDerivatives(); - setNotPeriodic(); - requestAtoms(atoms); + addValueWithDerivatives(); + setNotPeriodic(); + requestAtoms(atoms); } void Implicit::update_neighb() { - const double lower_c2 = 0.24 * 0.24; // this is the cut-off for bonded atoms - const unsigned size = getNumberOfAtoms(); - for (unsigned i=0; i<size; ++i) { - nl[i].clear(); - nlexpo[i].clear(); - const Vector posi = getPosition(i); - // Loop through neighboring atoms, add the ones below cutoff - for (unsigned j=i+1; j<size; ++j) { - const double d2 = delta(posi, getPosition(j)).modulo2(); - if (d2 < lower_c2 && j < i+14) { - // crude approximation for i-i+1/2 interactions, - // we want to exclude atoms separated by less than three bonds - continue; - } - // We choose the maximum lambda value and use a more conservative cutoff - double mlambda = 1./parameter[i][2]; - if (1./parameter[j][2] > mlambda) mlambda = 1./parameter[j][2]; - const double c2 = (4. * mlambda + buffer) * (4. * mlambda + buffer); - if (d2 < c2 ) { - nl[i].push_back(j); - if(parameter[i][2] == parameter[j][2] && parameter[i][3] == parameter[j][3]) { - nlexpo[i].push_back(true); - } else nlexpo[i].push_back(false); - } - } + const double lower_c2 = 0.24 * 0.24; // this is the cut-off for bonded atoms + const unsigned size = getNumberOfAtoms(); + for (unsigned i=0; i<size; ++i) { + nl[i].clear(); + nlexpo[i].clear(); + const Vector posi = getPosition(i); + // Loop through neighboring atoms, add the ones below cutoff + for (unsigned j=i+1; j<size; ++j) { + const double d2 = delta(posi, getPosition(j)).modulo2(); + if (d2 < lower_c2 && j < i+14) { + // crude approximation for i-i+1/2 interactions, + // we want to exclude atoms separated by less than three bonds + continue; + } + // We choose the maximum lambda value and use a more conservative cutoff + double mlambda = 1./parameter[i][2]; + if (1./parameter[j][2] > mlambda) mlambda = 1./parameter[j][2]; + const double c2 = (4. * mlambda + buffer) * (4. * mlambda + buffer); + if (d2 < c2 ) { + nl[i].push_back(j); + if(parameter[i][2] == parameter[j][2] && parameter[i][3] == parameter[j][3]) { + nlexpo[i].push_back(true); + } else nlexpo[i].push_back(false); + } } + } } void Implicit::calculate() { - if(pbc) makeWhole(); - if(getExchangeStep()) nl_update = 0; - if (nl_update == 0) { - update_neighb(); - } + if(pbc) makeWhole(); + if(getExchangeStep()) nl_update = 0; + if (nl_update == 0) { + update_neighb(); + } - const unsigned size=getNumberOfAtoms(); - double bias = 0.0; - Tensor deriv_box; - unsigned nt=OpenMP::getNumThreads(); - const unsigned nn=nl.size(); - if(nt*10>nn) nt=nn/10; - if(nt==0)nt=1; - #pragma omp parallel num_threads(nt) - { - vector<Vector> deriv_omp(size); - #pragma omp for reduction(+:bias) - for (unsigned i=0; i<size; ++i) { - const Vector posi = getPosition(i); - double fedensity = 0.0; - Vector deriv_i; - const double vdw_volume_i = parameter[i][0]; - const double delta_g_free_i = parameter[i][1]; - const double inv_lambda_i = parameter[i][2]; - const double vdw_radius_i = parameter[i][3]; - - // The pairwise interactions are unsymmetric, but we can get away with calculating the distance only once - for (unsigned i_nl=0; i_nl<nl[i].size(); ++i_nl) { - const unsigned j = nl[i][i_nl]; - const double vdw_volume_j = parameter[j][0]; - const double delta_g_free_j = parameter[j][1]; - const double inv_lambda_j = parameter[j][2]; - const double vdw_radius_j = parameter[j][3]; + const unsigned size=getNumberOfAtoms(); + double bias = 0.0; + Tensor deriv_box; + unsigned nt=OpenMP::getNumThreads(); + const unsigned nn=nl.size(); + if(nt*10>nn) nt=nn/10; + if(nt==0)nt=1; + #pragma omp parallel num_threads(nt) + { + vector<Vector> deriv_omp(size); + #pragma omp for reduction(+:bias) + for (unsigned i=0; i<size; ++i) { + const Vector posi = getPosition(i); + double fedensity = 0.0; + Vector deriv_i; + const double vdw_volume_i = parameter[i][0]; + const double delta_g_free_i = parameter[i][1]; + const double inv_lambda_i = parameter[i][2]; + const double vdw_radius_i = parameter[i][3]; - const Vector dist = delta(posi, getPosition(j)); - const double rij = dist.modulo(); - const double inv_rij = 1.0 / rij; - const double inv_rij2 = inv_rij * inv_rij; - const double fact_ij = inv_rij2 * delta_g_free_i * vdw_volume_j * INV_PI_SQRT_PI* inv_lambda_i; - const double fact_ji = inv_rij2 * delta_g_free_j * vdw_volume_i * INV_PI_SQRT_PI* inv_lambda_j; - double deriv = 0.; + // The pairwise interactions are unsymmetric, but we can get away with calculating the distance only once + for (unsigned i_nl=0; i_nl<nl[i].size(); ++i_nl) { + const unsigned j = nl[i][i_nl]; + const double vdw_volume_j = parameter[j][0]; + const double delta_g_free_j = parameter[j][1]; + const double inv_lambda_j = parameter[j][2]; + const double vdw_radius_j = parameter[j][3]; - // in this case we can calculate a single exponential - if(!nlexpo[i][i_nl]) { - // i-j interaction - if(inv_rij > 0.25*inv_lambda_i) - { - const double inv_lambda2_i = inv_lambda_i * inv_lambda_i; - const double rij_vdwr_diff = rij - vdw_radius_i; - const double expo = exp(-inv_lambda2_i * rij_vdwr_diff * rij_vdwr_diff); - const double fact = expo * fact_ij; - fedensity += fact; - deriv += inv_rij * fact * (inv_rij + rij_vdwr_diff * inv_lambda2_i); - } + const Vector dist = delta(posi, getPosition(j)); + const double rij = dist.modulo(); + const double inv_rij = 1.0 / rij; + const double inv_rij2 = inv_rij * inv_rij; + const double fact_ij = inv_rij2 * delta_g_free_i * vdw_volume_j * INV_PI_SQRT_PI* inv_lambda_i; + const double fact_ji = inv_rij2 * delta_g_free_j * vdw_volume_i * INV_PI_SQRT_PI* inv_lambda_j; + double deriv = 0.; - // j-i interaction - if(inv_rij > 0.25*inv_lambda_j) - { - const double inv_lambda2_j = inv_lambda_j * inv_lambda_j; - const double rij_vdwr_diff = rij - vdw_radius_j; - const double expo = exp(-inv_lambda2_j * rij_vdwr_diff * rij_vdwr_diff); - const double fact = expo * fact_ji; - fedensity += fact; - deriv += inv_rij * fact * (inv_rij + rij_vdwr_diff * inv_lambda2_j); - } - } else { - // i-j interaction - if(inv_rij > 0.25*inv_lambda_i) - { - const double inv_lambda2 = inv_lambda_i * inv_lambda_i; - const double rij_vdwr_diff = rij - vdw_radius_i; - const double expo = exp(-inv_lambda2 * rij_vdwr_diff * rij_vdwr_diff); - const double fact = expo*(fact_ij + fact_ji); - fedensity += fact; - deriv += inv_rij * fact * (inv_rij + rij_vdwr_diff * inv_lambda2); - } - } + // in this case we can calculate a single exponential + if(!nlexpo[i][i_nl]) { + // i-j interaction + if(inv_rij > 0.25*inv_lambda_i) + { + const double inv_lambda2_i = inv_lambda_i * inv_lambda_i; + const double rij_vdwr_diff = rij - vdw_radius_i; + const double expo = exp(-inv_lambda2_i * rij_vdwr_diff * rij_vdwr_diff); + const double fact = expo * fact_ij; + fedensity += fact; + deriv += inv_rij * fact * (inv_rij + rij_vdwr_diff * inv_lambda2_i); + } - const Vector dd = deriv*dist; - deriv_i += dd; - deriv_omp[j] -= dd; - } - deriv_omp[i] += deriv_i; - bias += - 0.5 * fedensity; - } - #pragma omp critical - for(unsigned i=0;i<size;i++) { - setAtomsDerivatives(i, -deriv_omp[i]); - deriv_box += Tensor(getPosition(i), -deriv_omp[i]); + // j-i interaction + if(inv_rij > 0.25*inv_lambda_j) + { + const double inv_lambda2_j = inv_lambda_j * inv_lambda_j; + const double rij_vdwr_diff = rij - vdw_radius_j; + const double expo = exp(-inv_lambda2_j * rij_vdwr_diff * rij_vdwr_diff); + const double fact = expo * fact_ji; + fedensity += fact; + deriv += inv_rij * fact * (inv_rij + rij_vdwr_diff * inv_lambda2_j); + } + } else { + // i-j interaction + if(inv_rij > 0.25*inv_lambda_i) + { + const double inv_lambda2 = inv_lambda_i * inv_lambda_i; + const double rij_vdwr_diff = rij - vdw_radius_i; + const double expo = exp(-inv_lambda2 * rij_vdwr_diff * rij_vdwr_diff); + const double fact = expo*(fact_ij + fact_ji); + fedensity += fact; + deriv += inv_rij * fact * (inv_rij + rij_vdwr_diff * inv_lambda2); + } } + + const Vector dd = deriv*dist; + deriv_i += dd; + deriv_omp[j] -= dd; + } + deriv_omp[i] += deriv_i; + bias += - 0.5 * fedensity; } + #pragma omp critical + for(unsigned i=0; i<size; i++) { + setAtomsDerivatives(i, -deriv_omp[i]); + deriv_box += Tensor(getPosition(i), -deriv_omp[i]); + } + } - setBoxDerivatives(-deriv_box); - setValue(delta_g_ref + bias); + setBoxDerivatives(-deriv_box); + setValue(delta_g_ref + bias); - // Keep track of the neighbourlist updates - ++nl_update; - if (nl_update == stride) { - nl_update = 0; - } + // Keep track of the neighbourlist updates + ++nl_update; + if (nl_update == stride) { + nl_update = 0; + } } void Implicit::setupConstants(const vector<AtomNumber> &atoms, vector<vector<double> > ¶meter, bool tcorr) { - vector<vector<double> > parameter_temp; - parameter_temp.resize(atoms.size()); - map<string, vector<double> > valuemap; - map<string, map<string, string> > typemap; - valuemap = setupValueMap(); - typemap = setupTypeMap(); - vector<SetupMolInfo*> moldat = plumed.getActionSet().select<SetupMolInfo*>(); - if (moldat.size() == 1) { - log << " MOLINFO DATA found, using proper atom names\n"; - for(unsigned i=0; i<atoms.size(); ++i) { + vector<vector<double> > parameter_temp; + parameter_temp.resize(atoms.size()); + map<string, vector<double> > valuemap; + map<string, map<string, string> > typemap; + valuemap = setupValueMap(); + typemap = setupTypeMap(); + vector<SetupMolInfo*> moldat = plumed.getActionSet().select<SetupMolInfo*>(); + if (moldat.size() == 1) { + log << " MOLINFO DATA found, using proper atom names\n"; + for(unsigned i=0; i<atoms.size(); ++i) { - // Get atom and residue names - string Aname = moldat[0]->getAtomName(atoms[i]); - string Rname = moldat[0]->getResidueName(atoms[i]); - string Atype = typemap[Rname][Aname]; + // Get atom and residue names + string Aname = moldat[0]->getAtomName(atoms[i]); + string Rname = moldat[0]->getResidueName(atoms[i]); + string Atype = typemap[Rname][Aname]; - // Check for terminal COOH or COO- (different atomtypes & parameters!) - if (moldat[0]->getAtomName(atoms[i]) == "OT1") { - // We create a temporary AtomNumber object to access future atoms - unsigned ai = atoms[i].index(); - AtomNumber tmp_an; - tmp_an.setIndex(ai + 2); - if (moldat[0]->getAtomName(tmp_an) == "HT2") { - // COOH - Atype = "OB"; - } else { - // COO- - Atype = "OC"; - } - } - if (moldat[0]->getAtomName(atoms[i]) == "OT2") { - unsigned ai = atoms[i].index(); - AtomNumber tmp_an; - tmp_an.setIndex(ai + 1); - if (moldat[0]->getAtomName(tmp_an) == "HT2") { - // COOH - Atype = "OH1"; - } else { - // COO- - Atype = "OC"; - } - } + // Check for terminal COOH or COO- (different atomtypes & parameters!) + if (moldat[0]->getAtomName(atoms[i]) == "OT1") { + // We create a temporary AtomNumber object to access future atoms + unsigned ai = atoms[i].index(); + AtomNumber tmp_an; + tmp_an.setIndex(ai + 2); + if (moldat[0]->getAtomName(tmp_an) == "HT2") { + // COOH + Atype = "OB"; + } else { + // COO- + Atype = "OC"; + } + } + if (moldat[0]->getAtomName(atoms[i]) == "OT2") { + unsigned ai = atoms[i].index(); + AtomNumber tmp_an; + tmp_an.setIndex(ai + 1); + if (moldat[0]->getAtomName(tmp_an) == "HT2") { + // COOH + Atype = "OH1"; + } else { + // COO- + Atype = "OC"; + } + } - // Check for H-atoms - char type; - char first = Aname.at(0); + // Check for H-atoms + char type; + char first = Aname.at(0); - // GOLDEN RULE: type is first letter, if not a number - if (!isdigit(first)){ - type = first; - // otherwise is the second - } else { - type = Aname.at(1); - } + // GOLDEN RULE: type is first letter, if not a number + if (!isdigit(first)) { + type = first; + // otherwise is the second + } else { + type = Aname.at(1); + } - if (type == 'H') { - error("EEF1-SB does not allow the use of hydrogen atoms!\n"); - } + if (type == 'H') { + error("EEF1-SB does not allow the use of hydrogen atoms!\n"); + } - // Lookup atomtype in table or throw exception if its not there - try { - parameter_temp[i] = valuemap.at(Atype); - } catch (exception &e) { - log << "Type: " << Atype << " Name: " << Aname << " Residue: " << Rname << "\n"; - error("Invalid atom type!\n"); - } + // Lookup atomtype in table or throw exception if its not there + try { + parameter_temp[i] = valuemap.at(Atype); + } catch (exception &e) { + log << "Type: " << Atype << " Name: " << Aname << " Residue: " << Rname << "\n"; + error("Invalid atom type!\n"); + } - // Temperature correction - if (tcorr && parameter[i][1] > 0.0) { - const double t0 = 298.15; - const double delta_g_ref_t0 = parameter_temp[i][1]; - const double delta_h_ref_t0 = parameter_temp[i][3]; - const double delta_cp = parameter_temp[i][4]; - const double delta_s_ref_t0 = (delta_h_ref_t0 - delta_g_ref_t0) / t0; - const double t = plumed.getAtoms().getKbT() / plumed.getAtoms().getKBoltzmann(); - parameter_temp[i][1] -= delta_s_ref_t0 * (t - t0) - delta_cp * t * std::log(t / t0) + delta_cp * (t - t0); - parameter_temp[i][2] *= parameter_temp[i][1] / delta_g_ref_t0; - } - parameter[i][0] = parameter_temp[i][0]; - parameter[i][1] = parameter_temp[i][2]; - parameter[i][2] = parameter_temp[i][5]; - parameter[i][3] = parameter_temp[i][6]; - } - } else { - error("MOLINFO DATA not found\n"); + // Temperature correction + if (tcorr && parameter[i][1] > 0.0) { + const double t0 = 298.15; + const double delta_g_ref_t0 = parameter_temp[i][1]; + const double delta_h_ref_t0 = parameter_temp[i][3]; + const double delta_cp = parameter_temp[i][4]; + const double delta_s_ref_t0 = (delta_h_ref_t0 - delta_g_ref_t0) / t0; + const double t = plumed.getAtoms().getKbT() / plumed.getAtoms().getKBoltzmann(); + parameter_temp[i][1] -= delta_s_ref_t0 * (t - t0) - delta_cp * t * std::log(t / t0) + delta_cp * (t - t0); + parameter_temp[i][2] *= parameter_temp[i][1] / delta_g_ref_t0; + } + parameter[i][0] = parameter_temp[i][0]; + parameter[i][1] = parameter_temp[i][2]; + parameter[i][2] = parameter_temp[i][5]; + parameter[i][3] = parameter_temp[i][6]; } - for(unsigned i=0; i<atoms.size(); ++i) delta_g_ref += parameter_temp[i][1]; + } else { + error("MOLINFO DATA not found\n"); + } + for(unsigned i=0; i<atoms.size(); ++i) delta_g_ref += parameter_temp[i][1]; } map<string, map<string, string> > Implicit::setupTypeMap() { - map<string, map<string, string> > typemap; - typemap = { - {"ALA", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT3"}, - {"HB1", "HA3"}, - {"HB2", "HA3"}, - {"HB3", "HA3"}, - {"C", "C" }, - {"O", "O" } - } - }, - {"ARG", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT2"}, - {"HB1", "HA2"}, - {"HB2", "HA2"}, - {"CG", "CT2"}, - {"HG1", "HA2"}, - {"HG2", "HA2"}, - {"CD", "CT2"}, - {"HD1", "HA2"}, - {"HD2", "HA2"}, - {"NE", "NC2"}, - {"HE", "HC" }, - {"CZ", "C" }, - {"NH1", "NC2"}, - {"HH11", "HC" }, - {"HH12", "HC" }, - {"NH2", "NC2"}, - {"HH21", "HC" }, - {"HH22", "HC" }, - {"C", "C" }, - {"O", "O" } - } - }, - {"ASN", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT2"}, - {"HB1", "HA2"}, - {"HB2", "HA2"}, - {"CG", "CC" }, - {"OD1", "O" }, - {"ND2", "NH2"}, - {"HD21", "H" }, - {"HD22", "H" }, - {"C", "C" }, - {"O", "O" } - } - }, - {"ASPP", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT2"}, - {"HB1", "HA2"}, - {"HB2", "HA2"}, - {"CG", "CD" }, - {"OD1", "OB" }, - {"OD2", "OH1"}, - {"HD2", "H" }, - {"C", "C" }, - {"O", "O" } - } - }, - {"ASP", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT2"}, - {"HB1", "HA2"}, - {"HB2", "HA2"}, - {"CG", "CC" }, - {"OD1", "OC" }, - {"OD2", "OC" }, - {"C", "C" }, - {"O", "O" } - } - }, - {"CYS", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT2"}, - {"HB1", "HA2"}, - {"HB2", "HA2"}, - {"SG", "S" }, - {"HG1", "HS" }, - {"C", "C" }, - {"O", "O" } - } - }, - {"GLN", { - {"N", "NH1" }, - {"HN", "H" }, - {"CA", "CT1" }, - {"HA", "HB1" }, - {"CB", "CT2" }, - {"HB1", "HA2" }, - {"HB2", "HA2" }, - {"CG", "CT2" }, - {"HG1", "HA2" }, - {"HG2", "HA2" }, - {"CD", "CC" }, - {"OE1", "O" }, - {"NE2", "NH2" }, - {"HE21", "H" }, - {"HE22", "H" }, - {"C", "C" }, - {"O", "O" } - } - }, - {"GLUP", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT2"}, - {"HB1", "HA2"}, - {"HB2", "HA2"}, - {"CG", "CT2"}, - {"HG1", "HA2"}, - {"HG2", "HA2"}, - {"CD", "CD" }, - {"OE1", "OB" }, - {"OE2", "OH1"}, - {"HE2", "H" }, - {"C", "C" }, - {"O", "O" } - } - }, - {"GLU", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT2"}, - {"HB1", "HA2"}, - {"HB2", "HA2"}, - {"CG", "CT2"}, - {"HG1", "HA2"}, - {"HG2", "HA2"}, - {"CD", "CC" }, - {"OE1", "OC" }, - {"OE2", "OC" }, - {"C", "C" }, - {"O", "O" } - } - }, - {"GLY", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT2"}, - {"HA1", "HB2"}, - {"HA2", "HB2"}, - {"C", "C" }, - {"O", "O" } - } - }, - {"HSD", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT2"}, - {"HB1", "HA2"}, - {"HB2", "HA2"}, - {"ND1", "NR1"}, - {"HD1", "H" }, - {"CG", "CPH1"}, - {"CE1", "CPH2"}, - {"HE1", "HR1"}, - {"NE2", "NR2"}, - {"CD2", "CPH1"}, - {"HD2", "HR3"}, - {"C", "C" }, - {"O", "O" } - } - }, - {"HIS", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT2"}, - {"HB1", "HA2"}, - {"HB2", "HA2"}, - {"ND1", "NR2"}, - {"CG", "CPH1"}, - {"CE1", "CPH2"}, - {"HE1", "HR1"}, - {"NE2", "NR1"}, - {"HE2", "H" }, - {"CD2", "CPH1"}, - {"HD2", "HR3"}, - {"C", "C" }, - {"O", "O" } - } - }, - {"HSE", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT2"}, - {"HB1", "HA2"}, - {"HB2", "HA2"}, - {"ND1", "NR2"}, - {"CG", "CPH1"}, - {"CE1", "CPH2"}, - {"HE1", "HR1"}, - {"NE2", "NR1"}, - {"HE2", "H" }, - {"CD2", "CPH1"}, - {"HD2", "HR3"}, - {"C", "C" }, - {"O", "O" } - } - }, - {"HSP", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT2"}, - {"HB1", "HA2"}, - {"HB2", "HA2"}, - {"CD2", "CPH1"}, - {"HD2", "HR1"}, - {"CG", "CPH1"}, - {"NE2", "NR3"}, - {"HE2", "H" }, - {"ND1", "NR3"}, - {"HD1", "H" }, - {"CE1", "CPH2"}, - {"HE1", "HR2"}, - {"C", "C" }, - {"O", "O" } - } - }, - {"ILE", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT1"}, - {"HB", "HA1"}, - {"CG2", "CT3"}, - {"HG21", "HA3"}, - {"HG22", "HA3"}, - {"HG23", "HA3"}, - {"CG1", "CT2"}, - {"HG11", "HA2"}, - {"HG12", "HA2"}, - {"CD", "CT3"}, - {"HD1", "HA3"}, - {"HD2", "HA3"}, - {"HD3", "HA3"}, - {"C", "C" }, - {"O", "O" } - } - }, - {"LEU", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT2"}, - {"HB1", "HA2"}, - {"HB2", "HA2"}, - {"CG", "CT1"}, - {"HG", "HA1"}, - {"CD1", "CT3"}, - {"HD11", "HA3"}, - {"HD12", "HA3"}, - {"HD13", "HA3"}, - {"CD2", "CT3"}, - {"HD21", "HA3"}, - {"HD22", "HA3"}, - {"HD23", "HA3"}, - {"C", "C" }, - {"O", "O" } - } - }, - {"LYS", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT2"}, - {"HB1", "HA2"}, - {"HB2", "HA2"}, - {"CG", "CT2"}, - {"HG1", "HA2"}, - {"HG2", "HA2"}, - {"CD", "CT2"}, - {"HD1", "HA2"}, - {"HD2", "HA2"}, - {"CE", "CT2"}, - {"HE1", "HA2"}, - {"HE2", "HA2"}, - {"NZ", "NH3"}, - {"HZ1", "HC" }, - {"HZ2", "HC" }, - {"HZ3", "HC" }, - {"C", "C" }, - {"O", "O" } - } - }, - {"MET", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT2"}, - {"HB1", "HA2"}, - {"HB2", "HA2"}, - {"CG", "CT2"}, - {"HG1", "HA2"}, - {"HG2", "HA2"}, - {"SD", "S" }, - {"CE", "CT3"}, - {"HE1", "HA3"}, - {"HE2", "HA3"}, - {"HE3", "HA3"}, - {"C", "C" }, - {"O", "O" } - } - }, - {"PHE", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT2"}, - {"HB1", "HA2"}, - {"HB2", "HA2"}, - {"CG", "CA" }, - {"CD1", "CA" }, - {"HD1", "HP" }, - {"CE1", "CA" }, - {"HE1", "HP" }, - {"CZ", "CA" }, - {"HZ", "HP" }, - {"CD2", "CA" }, - {"HD2", "HP" }, - {"CE2", "CA" }, - {"HE2", "HP" }, - {"C", "C" }, - {"O", "O" } - } - }, - {"PRO", { - {"N", "N" }, - {"CD", "CP3"}, - {"HD1", "HA2"}, - {"HD2", "HA2"}, - {"CA", "CP1"}, - {"HA", "HB1"}, - {"CB", "CP2"}, - {"HB1", "HA2"}, - {"HB2", "HA2"}, - {"CG", "CP2"}, - {"HG1", "HA2"}, - {"HG2", "HA2"}, - {"C", "C" }, - {"O", "O" } - } - }, - {"SER", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT2"}, - {"HB1", "HA2"}, - {"HB2", "HA2"}, - {"OG", "OH1"}, - {"HG1", "H" }, - {"C", "C" }, - {"O", "O" } - } - }, - {"THR", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT1"}, - {"HB", "HA1"}, - {"OG1", "OH1"}, - {"HG1", "H" }, - {"CG2", "CT3"}, - {"HG21", "HA3"}, - {"HG22", "HA3"}, - {"HG23", "HA3"}, - {"C", "C" }, - {"O", "O" } - } - }, - {"TRP", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT2"}, - {"HB1", "HA2"}, - {"HB2", "HA2"}, - {"CG", "CY" }, - {"CD1", "CA" }, - {"HD1", "HP" }, - {"NE1", "NY" }, - {"HE1", "H" }, - {"CE2", "CPT"}, - {"CD2", "CPT"}, - {"CE3", "CAI"}, - {"HE3", "HP" }, - {"CZ3", "CA" }, - {"HZ3", "HP" }, - {"CZ2", "CAI"}, - {"HZ2", "HP" }, - {"CH2", "CA" }, - {"HH2", "HP" }, - {"C", "C" }, - {"O", "O" } - } - }, - {"TYR", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT2"}, - {"HB1", "HA2"}, - {"HB2", "HA2"}, - {"CG", "CA" }, - {"CD1", "CA" }, - {"HD1", "HP" }, - {"CE1", "CA" }, - {"HE1", "HP" }, - {"CZ", "CA" }, - {"OH", "OH1"}, - {"HH", "H" }, - {"CD2", "CA" }, - {"HD2", "HP" }, - {"CE2", "CA" }, - {"HE2", "HP" }, - {"C", "C" }, - {"O", "O" } - } - }, - {"VAL", { - {"N", "NH1"}, - {"HN", "H" }, - {"CA", "CT1"}, - {"HA", "HB1"}, - {"CB", "CT1"}, - {"HB", "HA1"}, - {"CG1", "CT3"}, - {"HG11", "HA3"}, - {"HG12", "HA3"}, - {"HG13", "HA3"}, - {"CG2", "CT3"}, - {"HG21", "HA3"}, - {"HG22", "HA3"}, - {"HG23", "HA3"}, - {"C", "C" }, - {"O", "O" } - } - } - }; - return typemap; + map<string, map<string, string> > typemap; + typemap = { + { "ALA", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT3"}, + {"HB1", "HA3"}, + {"HB2", "HA3"}, + {"HB3", "HA3"}, + {"C", "C" }, + {"O", "O" } + } + }, + { "ARG", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT2"}, + {"HB1", "HA2"}, + {"HB2", "HA2"}, + {"CG", "CT2"}, + {"HG1", "HA2"}, + {"HG2", "HA2"}, + {"CD", "CT2"}, + {"HD1", "HA2"}, + {"HD2", "HA2"}, + {"NE", "NC2"}, + {"HE", "HC" }, + {"CZ", "C" }, + {"NH1", "NC2"}, + {"HH11", "HC" }, + {"HH12", "HC" }, + {"NH2", "NC2"}, + {"HH21", "HC" }, + {"HH22", "HC" }, + {"C", "C" }, + {"O", "O" } + } + }, + { "ASN", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT2"}, + {"HB1", "HA2"}, + {"HB2", "HA2"}, + {"CG", "CC" }, + {"OD1", "O" }, + {"ND2", "NH2"}, + {"HD21", "H" }, + {"HD22", "H" }, + {"C", "C" }, + {"O", "O" } + } + }, + { "ASPP", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT2"}, + {"HB1", "HA2"}, + {"HB2", "HA2"}, + {"CG", "CD" }, + {"OD1", "OB" }, + {"OD2", "OH1"}, + {"HD2", "H" }, + {"C", "C" }, + {"O", "O" } + } + }, + { "ASP", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT2"}, + {"HB1", "HA2"}, + {"HB2", "HA2"}, + {"CG", "CC" }, + {"OD1", "OC" }, + {"OD2", "OC" }, + {"C", "C" }, + {"O", "O" } + } + }, + { "CYS", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT2"}, + {"HB1", "HA2"}, + {"HB2", "HA2"}, + {"SG", "S" }, + {"HG1", "HS" }, + {"C", "C" }, + {"O", "O" } + } + }, + { "GLN", { + {"N", "NH1" }, + {"HN", "H" }, + {"CA", "CT1" }, + {"HA", "HB1" }, + {"CB", "CT2" }, + {"HB1", "HA2" }, + {"HB2", "HA2" }, + {"CG", "CT2" }, + {"HG1", "HA2" }, + {"HG2", "HA2" }, + {"CD", "CC" }, + {"OE1", "O" }, + {"NE2", "NH2" }, + {"HE21", "H" }, + {"HE22", "H" }, + {"C", "C" }, + {"O", "O" } + } + }, + { "GLUP", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT2"}, + {"HB1", "HA2"}, + {"HB2", "HA2"}, + {"CG", "CT2"}, + {"HG1", "HA2"}, + {"HG2", "HA2"}, + {"CD", "CD" }, + {"OE1", "OB" }, + {"OE2", "OH1"}, + {"HE2", "H" }, + {"C", "C" }, + {"O", "O" } + } + }, + { "GLU", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT2"}, + {"HB1", "HA2"}, + {"HB2", "HA2"}, + {"CG", "CT2"}, + {"HG1", "HA2"}, + {"HG2", "HA2"}, + {"CD", "CC" }, + {"OE1", "OC" }, + {"OE2", "OC" }, + {"C", "C" }, + {"O", "O" } + } + }, + { "GLY", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT2"}, + {"HA1", "HB2"}, + {"HA2", "HB2"}, + {"C", "C" }, + {"O", "O" } + } + }, + { "HSD", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT2"}, + {"HB1", "HA2"}, + {"HB2", "HA2"}, + {"ND1", "NR1"}, + {"HD1", "H" }, + {"CG", "CPH1"}, + {"CE1", "CPH2"}, + {"HE1", "HR1"}, + {"NE2", "NR2"}, + {"CD2", "CPH1"}, + {"HD2", "HR3"}, + {"C", "C" }, + {"O", "O" } + } + }, + { "HIS", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT2"}, + {"HB1", "HA2"}, + {"HB2", "HA2"}, + {"ND1", "NR2"}, + {"CG", "CPH1"}, + {"CE1", "CPH2"}, + {"HE1", "HR1"}, + {"NE2", "NR1"}, + {"HE2", "H" }, + {"CD2", "CPH1"}, + {"HD2", "HR3"}, + {"C", "C" }, + {"O", "O" } + } + }, + { "HSE", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT2"}, + {"HB1", "HA2"}, + {"HB2", "HA2"}, + {"ND1", "NR2"}, + {"CG", "CPH1"}, + {"CE1", "CPH2"}, + {"HE1", "HR1"}, + {"NE2", "NR1"}, + {"HE2", "H" }, + {"CD2", "CPH1"}, + {"HD2", "HR3"}, + {"C", "C" }, + {"O", "O" } + } + }, + { "HSP", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT2"}, + {"HB1", "HA2"}, + {"HB2", "HA2"}, + {"CD2", "CPH1"}, + {"HD2", "HR1"}, + {"CG", "CPH1"}, + {"NE2", "NR3"}, + {"HE2", "H" }, + {"ND1", "NR3"}, + {"HD1", "H" }, + {"CE1", "CPH2"}, + {"HE1", "HR2"}, + {"C", "C" }, + {"O", "O" } + } + }, + { "ILE", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT1"}, + {"HB", "HA1"}, + {"CG2", "CT3"}, + {"HG21", "HA3"}, + {"HG22", "HA3"}, + {"HG23", "HA3"}, + {"CG1", "CT2"}, + {"HG11", "HA2"}, + {"HG12", "HA2"}, + {"CD", "CT3"}, + {"HD1", "HA3"}, + {"HD2", "HA3"}, + {"HD3", "HA3"}, + {"C", "C" }, + {"O", "O" } + } + }, + { "LEU", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT2"}, + {"HB1", "HA2"}, + {"HB2", "HA2"}, + {"CG", "CT1"}, + {"HG", "HA1"}, + {"CD1", "CT3"}, + {"HD11", "HA3"}, + {"HD12", "HA3"}, + {"HD13", "HA3"}, + {"CD2", "CT3"}, + {"HD21", "HA3"}, + {"HD22", "HA3"}, + {"HD23", "HA3"}, + {"C", "C" }, + {"O", "O" } + } + }, + { "LYS", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT2"}, + {"HB1", "HA2"}, + {"HB2", "HA2"}, + {"CG", "CT2"}, + {"HG1", "HA2"}, + {"HG2", "HA2"}, + {"CD", "CT2"}, + {"HD1", "HA2"}, + {"HD2", "HA2"}, + {"CE", "CT2"}, + {"HE1", "HA2"}, + {"HE2", "HA2"}, + {"NZ", "NH3"}, + {"HZ1", "HC" }, + {"HZ2", "HC" }, + {"HZ3", "HC" }, + {"C", "C" }, + {"O", "O" } + } + }, + { "MET", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT2"}, + {"HB1", "HA2"}, + {"HB2", "HA2"}, + {"CG", "CT2"}, + {"HG1", "HA2"}, + {"HG2", "HA2"}, + {"SD", "S" }, + {"CE", "CT3"}, + {"HE1", "HA3"}, + {"HE2", "HA3"}, + {"HE3", "HA3"}, + {"C", "C" }, + {"O", "O" } + } + }, + { "PHE", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT2"}, + {"HB1", "HA2"}, + {"HB2", "HA2"}, + {"CG", "CA" }, + {"CD1", "CA" }, + {"HD1", "HP" }, + {"CE1", "CA" }, + {"HE1", "HP" }, + {"CZ", "CA" }, + {"HZ", "HP" }, + {"CD2", "CA" }, + {"HD2", "HP" }, + {"CE2", "CA" }, + {"HE2", "HP" }, + {"C", "C" }, + {"O", "O" } + } + }, + { "PRO", { + {"N", "N" }, + {"CD", "CP3"}, + {"HD1", "HA2"}, + {"HD2", "HA2"}, + {"CA", "CP1"}, + {"HA", "HB1"}, + {"CB", "CP2"}, + {"HB1", "HA2"}, + {"HB2", "HA2"}, + {"CG", "CP2"}, + {"HG1", "HA2"}, + {"HG2", "HA2"}, + {"C", "C" }, + {"O", "O" } + } + }, + { "SER", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT2"}, + {"HB1", "HA2"}, + {"HB2", "HA2"}, + {"OG", "OH1"}, + {"HG1", "H" }, + {"C", "C" }, + {"O", "O" } + } + }, + { "THR", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT1"}, + {"HB", "HA1"}, + {"OG1", "OH1"}, + {"HG1", "H" }, + {"CG2", "CT3"}, + {"HG21", "HA3"}, + {"HG22", "HA3"}, + {"HG23", "HA3"}, + {"C", "C" }, + {"O", "O" } + } + }, + { "TRP", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT2"}, + {"HB1", "HA2"}, + {"HB2", "HA2"}, + {"CG", "CY" }, + {"CD1", "CA" }, + {"HD1", "HP" }, + {"NE1", "NY" }, + {"HE1", "H" }, + {"CE2", "CPT"}, + {"CD2", "CPT"}, + {"CE3", "CAI"}, + {"HE3", "HP" }, + {"CZ3", "CA" }, + {"HZ3", "HP" }, + {"CZ2", "CAI"}, + {"HZ2", "HP" }, + {"CH2", "CA" }, + {"HH2", "HP" }, + {"C", "C" }, + {"O", "O" } + } + }, + { "TYR", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT2"}, + {"HB1", "HA2"}, + {"HB2", "HA2"}, + {"CG", "CA" }, + {"CD1", "CA" }, + {"HD1", "HP" }, + {"CE1", "CA" }, + {"HE1", "HP" }, + {"CZ", "CA" }, + {"OH", "OH1"}, + {"HH", "H" }, + {"CD2", "CA" }, + {"HD2", "HP" }, + {"CE2", "CA" }, + {"HE2", "HP" }, + {"C", "C" }, + {"O", "O" } + } + }, + { "VAL", { + {"N", "NH1"}, + {"HN", "H" }, + {"CA", "CT1"}, + {"HA", "HB1"}, + {"CB", "CT1"}, + {"HB", "HA1"}, + {"CG1", "CT3"}, + {"HG11", "HA3"}, + {"HG12", "HA3"}, + {"HG13", "HA3"}, + {"CG2", "CT3"}, + {"HG21", "HA3"}, + {"HG22", "HA3"}, + {"HG23", "HA3"}, + {"C", "C" }, + {"O", "O" } + } + } + }; + return typemap; } map<string, vector<double> > Implicit::setupValueMap() { - // Volume ∆Gref ∆Gfree ∆H ∆Cp λ vdw_radius - map<string, vector<double> > valuemap; - valuemap = { - {"C", { - ANG3_TO_NM3 * 14.720, - KCAL_TO_KJ * 0.000, - KCAL_TO_KJ * 0.000, - KCAL_TO_KJ * 0.000, - KCAL_TO_KJ * 0.0, - 1. / (ANG_TO_NM * 3.5), - 0.20, - } - }, - {"CD", { - ANG3_TO_NM3 * 14.720, - KCAL_TO_KJ * 0.000, - KCAL_TO_KJ * 0.000, - KCAL_TO_KJ * 0.000, - KCAL_TO_KJ * 0.0, - 1. / (ANG_TO_NM * 3.5), - 0.20, - } - }, - {"CT1", { - ANG3_TO_NM3 * 11.507, - KCAL_TO_KJ * -0.187, - KCAL_TO_KJ * -0.187, - KCAL_TO_KJ * 0.876, - KCAL_TO_KJ * 0.0, - 1. / (ANG_TO_NM * 3.5), - 0.20, - } - }, - {"CT2", { - ANG3_TO_NM3 * 18.850, - KCAL_TO_KJ * 0.372, - KCAL_TO_KJ * 0.372, - KCAL_TO_KJ * -0.610, - KCAL_TO_KJ * 18.6, - 1. / (ANG_TO_NM * 3.5), - 0.20, - } - }, - {"CT2A", { - ANG3_TO_NM3 * 18.666, - KCAL_TO_KJ * 0.372, - KCAL_TO_KJ * 0.372, - KCAL_TO_KJ * -0.610, - KCAL_TO_KJ * 18.6, - 1. / (ANG_TO_NM * 3.5), - 0.20, - } - }, - {"CT3", { - ANG3_TO_NM3 * 27.941, - KCAL_TO_KJ * 1.089, - KCAL_TO_KJ * 1.089, - KCAL_TO_KJ * -1.779, - KCAL_TO_KJ * 35.6, - 1. / (ANG_TO_NM * 3.5), - 0.204, - } - }, - {"CPH1", { - ANG3_TO_NM3 * 5.275, - KCAL_TO_KJ * 0.057, - KCAL_TO_KJ * 0.080, - KCAL_TO_KJ * -0.973, - KCAL_TO_KJ * 6.9, - 1. / (ANG_TO_NM * 3.5), - 0.18, - } - }, - {"CPH2", { - ANG3_TO_NM3 * 11.796, - KCAL_TO_KJ * 0.057, - KCAL_TO_KJ * 0.080, - KCAL_TO_KJ * -0.973, - KCAL_TO_KJ * 6.9, - 1. / (ANG_TO_NM * 3.5), - 0.18, - } - }, - {"CPT", { - ANG3_TO_NM3 * 4.669, - KCAL_TO_KJ * -0.890, - KCAL_TO_KJ * -0.890, - KCAL_TO_KJ * 2.220, - KCAL_TO_KJ * 6.9, - 1. / (ANG_TO_NM * 3.5), - 0.186, - } - }, - {"CY", { - ANG3_TO_NM3 * 10.507, - KCAL_TO_KJ * -0.890, - KCAL_TO_KJ * -0.890, - KCAL_TO_KJ * 2.220, - KCAL_TO_KJ * 6.9, - 1. / (ANG_TO_NM * 3.5), - 0.199, - } - }, - {"CP1", { - ANG3_TO_NM3 * 25.458, - KCAL_TO_KJ * -0.187, - KCAL_TO_KJ * -0.187, - KCAL_TO_KJ * 0.876, - KCAL_TO_KJ * 0.0, - 1. / (ANG_TO_NM * 3.5), - 0.227, - } - }, - {"CP2", { - ANG3_TO_NM3 * 19.880, - KCAL_TO_KJ * 0.372, - KCAL_TO_KJ * 0.372, - KCAL_TO_KJ * -0.610, - KCAL_TO_KJ * 18.6, - 1. / (ANG_TO_NM * 3.5), - 0.217, - } - }, - {"CP3", { - ANG3_TO_NM3 * 26.731, - KCAL_TO_KJ * 0.372, - KCAL_TO_KJ * 0.372, - KCAL_TO_KJ * -0.610, - KCAL_TO_KJ * 18.6, - 1. / (ANG_TO_NM * 3.5), - 0.217, - } - }, - {"CC", { - ANG3_TO_NM3 * 16.539, - KCAL_TO_KJ * 0.000, - KCAL_TO_KJ * 0.000, - KCAL_TO_KJ * 0.000, - KCAL_TO_KJ * 0.0, - 1. / (ANG_TO_NM * 3.5), - 0.20, - } - }, - {"CAI", { - ANG3_TO_NM3 * 18.249, - KCAL_TO_KJ * 0.057, - KCAL_TO_KJ * 0.057, - KCAL_TO_KJ * -0.973, - KCAL_TO_KJ * 6.9, - 1. / (ANG_TO_NM * 3.5), - 0.199, - } - }, - {"CA", { - ANG3_TO_NM3 * 18.249, - KCAL_TO_KJ * 0.057, - KCAL_TO_KJ * 0.057, - KCAL_TO_KJ * -0.973, - KCAL_TO_KJ * 6.9, - 1. / (ANG_TO_NM * 3.5), - 0.199, - } - }, - {"N", { - ANG3_TO_NM3 * 0.000, - KCAL_TO_KJ * -1.000, - KCAL_TO_KJ * -1.000, - KCAL_TO_KJ * -1.250, - KCAL_TO_KJ * 8.8, - 1. / (ANG_TO_NM * 3.5), - 0.185, - } - }, - {"NR1", { - ANG3_TO_NM3 * 15.273, - KCAL_TO_KJ * -5.950, - KCAL_TO_KJ * -5.950, - KCAL_TO_KJ * -9.059, - KCAL_TO_KJ * -8.8, - 1. / (ANG_TO_NM * 3.5), - 0.185, - } - }, - {"NR2", { - ANG3_TO_NM3 * 15.111, - KCAL_TO_KJ * -3.820, - KCAL_TO_KJ * -3.820, - KCAL_TO_KJ * -4.654, - KCAL_TO_KJ * -8.8, - 1. / (ANG_TO_NM * 3.5), - 0.185, - } - }, - {"NR3", { - ANG3_TO_NM3 * 15.071, - KCAL_TO_KJ * -5.950, - KCAL_TO_KJ * -5.950, - KCAL_TO_KJ * -9.059, - KCAL_TO_KJ * -8.8, - 1. / (ANG_TO_NM * 3.5), - 0.185, - } - }, - {"NH1", { - ANG3_TO_NM3 * 10.197, - KCAL_TO_KJ * -5.950, - KCAL_TO_KJ * -5.950, - KCAL_TO_KJ * -9.059, - KCAL_TO_KJ * -8.8, - 1. / (ANG_TO_NM * 3.5), - 0.185, - } - }, - {"NH2", { - ANG3_TO_NM3 * 18.182, - KCAL_TO_KJ * -5.950, - KCAL_TO_KJ * -5.950, - KCAL_TO_KJ * -9.059, - KCAL_TO_KJ * -8.8, - 1. / (ANG_TO_NM * 3.5), - 0.185, - } - }, - {"NH3", { - ANG3_TO_NM3 * 18.817, - KCAL_TO_KJ * -20.000, - KCAL_TO_KJ * -20.000, - KCAL_TO_KJ * -25.000, - KCAL_TO_KJ * -18.0, - 1. / (ANG_TO_NM * 6.0), - 0.185, - } - }, - {"NC2", { - ANG3_TO_NM3 * 18.215, - KCAL_TO_KJ * -10.000, - KCAL_TO_KJ * -10.000, - KCAL_TO_KJ * -12.000, - KCAL_TO_KJ * -7.0, - 1. / (ANG_TO_NM * 6.0), - 0.185, - } - }, - {"NY", { - ANG3_TO_NM3 * 12.001, - KCAL_TO_KJ * -5.950, - KCAL_TO_KJ * -5.950, - KCAL_TO_KJ * -9.059, - KCAL_TO_KJ * -8.8, - 1. / (ANG_TO_NM * 3.5), - 0.185, - } - }, - {"NP", { - ANG3_TO_NM3 * 4.993, - KCAL_TO_KJ * -20.000, - KCAL_TO_KJ * -20.000, - KCAL_TO_KJ * -25.000, - KCAL_TO_KJ * -18.0, - 1. / (ANG_TO_NM * 6.0), - 0.185, - } - }, - {"O", { - ANG3_TO_NM3 * 11.772, - KCAL_TO_KJ * -5.330, - KCAL_TO_KJ * -5.330, - KCAL_TO_KJ * -5.787, - KCAL_TO_KJ * -8.8, - 1. / (ANG_TO_NM * 3.5), - 0.170, - } - }, - {"OB", { - ANG3_TO_NM3 * 11.694, - KCAL_TO_KJ * -5.330, - KCAL_TO_KJ * -5.330, - KCAL_TO_KJ * -5.787, - KCAL_TO_KJ * -8.8, - 1. / (ANG_TO_NM * 3.5), - 0.170, - } - }, - {"OC", { - ANG3_TO_NM3 * 12.003, - KCAL_TO_KJ * -10.000, - KCAL_TO_KJ * -10.000, - KCAL_TO_KJ * -12.000, - KCAL_TO_KJ * -9.4, - 1. / (ANG_TO_NM * 6.0), - 0.170, - } - }, - {"OH1", { - ANG3_TO_NM3 * 15.528, - KCAL_TO_KJ * -5.920, - KCAL_TO_KJ * -5.920, - KCAL_TO_KJ * -9.264, - KCAL_TO_KJ * -11.2, - 1. / (ANG_TO_NM * 3.5), - 0.177, - } - }, - {"OS", { - ANG3_TO_NM3 * 6.774, - KCAL_TO_KJ * -2.900, - KCAL_TO_KJ * -2.900, - KCAL_TO_KJ * -3.150, - KCAL_TO_KJ * -4.8, - 1. / (ANG_TO_NM * 3.5), - 0.177, - } - }, - {"S", { - ANG3_TO_NM3 * 20.703, - KCAL_TO_KJ * -3.240, - KCAL_TO_KJ * -3.240, - KCAL_TO_KJ * -4.475, - KCAL_TO_KJ * -39.9, - 1. / (ANG_TO_NM * 3.5), - 0.20, - } - }, - {"SM", { - ANG3_TO_NM3 * 21.306, - KCAL_TO_KJ * -3.240, - KCAL_TO_KJ * -3.240, - KCAL_TO_KJ * -4.475, - KCAL_TO_KJ * -39.9, - 1. / (ANG_TO_NM * 3.5), - 0.197, - } - } - }; - return valuemap; -} + // Volume ∆Gref ∆Gfree ∆H ∆Cp λ vdw_radius + map<string, vector<double> > valuemap; + valuemap = { + { "C", { + ANG3_TO_NM3 * 14.720, + KCAL_TO_KJ * 0.000, + KCAL_TO_KJ * 0.000, + KCAL_TO_KJ * 0.000, + KCAL_TO_KJ * 0.0, + 1. / (ANG_TO_NM * 3.5), + 0.20, + } + }, + { "CD", { + ANG3_TO_NM3 * 14.720, + KCAL_TO_KJ * 0.000, + KCAL_TO_KJ * 0.000, + KCAL_TO_KJ * 0.000, + KCAL_TO_KJ * 0.0, + 1. / (ANG_TO_NM * 3.5), + 0.20, + } + }, + { "CT1", { + ANG3_TO_NM3 * 11.507, + KCAL_TO_KJ * -0.187, + KCAL_TO_KJ * -0.187, + KCAL_TO_KJ * 0.876, + KCAL_TO_KJ * 0.0, + 1. / (ANG_TO_NM * 3.5), + 0.20, + } + }, + { "CT2", { + ANG3_TO_NM3 * 18.850, + KCAL_TO_KJ * 0.372, + KCAL_TO_KJ * 0.372, + KCAL_TO_KJ * -0.610, + KCAL_TO_KJ * 18.6, + 1. / (ANG_TO_NM * 3.5), + 0.20, + } + }, + { "CT2A", { + ANG3_TO_NM3 * 18.666, + KCAL_TO_KJ * 0.372, + KCAL_TO_KJ * 0.372, + KCAL_TO_KJ * -0.610, + KCAL_TO_KJ * 18.6, + 1. / (ANG_TO_NM * 3.5), + 0.20, + } + }, + { "CT3", { + ANG3_TO_NM3 * 27.941, + KCAL_TO_KJ * 1.089, + KCAL_TO_KJ * 1.089, + KCAL_TO_KJ * -1.779, + KCAL_TO_KJ * 35.6, + 1. / (ANG_TO_NM * 3.5), + 0.204, + } + }, + { "CPH1", { + ANG3_TO_NM3 * 5.275, + KCAL_TO_KJ * 0.057, + KCAL_TO_KJ * 0.080, + KCAL_TO_KJ * -0.973, + KCAL_TO_KJ * 6.9, + 1. / (ANG_TO_NM * 3.5), + 0.18, + } + }, + { "CPH2", { + ANG3_TO_NM3 * 11.796, + KCAL_TO_KJ * 0.057, + KCAL_TO_KJ * 0.080, + KCAL_TO_KJ * -0.973, + KCAL_TO_KJ * 6.9, + 1. / (ANG_TO_NM * 3.5), + 0.18, + } + }, + { "CPT", { + ANG3_TO_NM3 * 4.669, + KCAL_TO_KJ * -0.890, + KCAL_TO_KJ * -0.890, + KCAL_TO_KJ * 2.220, + KCAL_TO_KJ * 6.9, + 1. / (ANG_TO_NM * 3.5), + 0.186, + } + }, + { "CY", { + ANG3_TO_NM3 * 10.507, + KCAL_TO_KJ * -0.890, + KCAL_TO_KJ * -0.890, + KCAL_TO_KJ * 2.220, + KCAL_TO_KJ * 6.9, + 1. / (ANG_TO_NM * 3.5), + 0.199, + } + }, + { "CP1", { + ANG3_TO_NM3 * 25.458, + KCAL_TO_KJ * -0.187, + KCAL_TO_KJ * -0.187, + KCAL_TO_KJ * 0.876, + KCAL_TO_KJ * 0.0, + 1. / (ANG_TO_NM * 3.5), + 0.227, + } + }, + { "CP2", { + ANG3_TO_NM3 * 19.880, + KCAL_TO_KJ * 0.372, + KCAL_TO_KJ * 0.372, + KCAL_TO_KJ * -0.610, + KCAL_TO_KJ * 18.6, + 1. / (ANG_TO_NM * 3.5), + 0.217, + } + }, + { "CP3", { + ANG3_TO_NM3 * 26.731, + KCAL_TO_KJ * 0.372, + KCAL_TO_KJ * 0.372, + KCAL_TO_KJ * -0.610, + KCAL_TO_KJ * 18.6, + 1. / (ANG_TO_NM * 3.5), + 0.217, + } + }, + { "CC", { + ANG3_TO_NM3 * 16.539, + KCAL_TO_KJ * 0.000, + KCAL_TO_KJ * 0.000, + KCAL_TO_KJ * 0.000, + KCAL_TO_KJ * 0.0, + 1. / (ANG_TO_NM * 3.5), + 0.20, + } + }, + { "CAI", { + ANG3_TO_NM3 * 18.249, + KCAL_TO_KJ * 0.057, + KCAL_TO_KJ * 0.057, + KCAL_TO_KJ * -0.973, + KCAL_TO_KJ * 6.9, + 1. / (ANG_TO_NM * 3.5), + 0.199, + } + }, + { "CA", { + ANG3_TO_NM3 * 18.249, + KCAL_TO_KJ * 0.057, + KCAL_TO_KJ * 0.057, + KCAL_TO_KJ * -0.973, + KCAL_TO_KJ * 6.9, + 1. / (ANG_TO_NM * 3.5), + 0.199, + } + }, + { "N", { + ANG3_TO_NM3 * 0.000, + KCAL_TO_KJ * -1.000, + KCAL_TO_KJ * -1.000, + KCAL_TO_KJ * -1.250, + KCAL_TO_KJ * 8.8, + 1. / (ANG_TO_NM * 3.5), + 0.185, + } + }, + { "NR1", { + ANG3_TO_NM3 * 15.273, + KCAL_TO_KJ * -5.950, + KCAL_TO_KJ * -5.950, + KCAL_TO_KJ * -9.059, + KCAL_TO_KJ * -8.8, + 1. / (ANG_TO_NM * 3.5), + 0.185, + } + }, + { "NR2", { + ANG3_TO_NM3 * 15.111, + KCAL_TO_KJ * -3.820, + KCAL_TO_KJ * -3.820, + KCAL_TO_KJ * -4.654, + KCAL_TO_KJ * -8.8, + 1. / (ANG_TO_NM * 3.5), + 0.185, + } + }, + { "NR3", { + ANG3_TO_NM3 * 15.071, + KCAL_TO_KJ * -5.950, + KCAL_TO_KJ * -5.950, + KCAL_TO_KJ * -9.059, + KCAL_TO_KJ * -8.8, + 1. / (ANG_TO_NM * 3.5), + 0.185, + } + }, + { "NH1", { + ANG3_TO_NM3 * 10.197, + KCAL_TO_KJ * -5.950, + KCAL_TO_KJ * -5.950, + KCAL_TO_KJ * -9.059, + KCAL_TO_KJ * -8.8, + 1. / (ANG_TO_NM * 3.5), + 0.185, + } + }, + { "NH2", { + ANG3_TO_NM3 * 18.182, + KCAL_TO_KJ * -5.950, + KCAL_TO_KJ * -5.950, + KCAL_TO_KJ * -9.059, + KCAL_TO_KJ * -8.8, + 1. / (ANG_TO_NM * 3.5), + 0.185, + } + }, + { "NH3", { + ANG3_TO_NM3 * 18.817, + KCAL_TO_KJ * -20.000, + KCAL_TO_KJ * -20.000, + KCAL_TO_KJ * -25.000, + KCAL_TO_KJ * -18.0, + 1. / (ANG_TO_NM * 6.0), + 0.185, + } + }, + { "NC2", { + ANG3_TO_NM3 * 18.215, + KCAL_TO_KJ * -10.000, + KCAL_TO_KJ * -10.000, + KCAL_TO_KJ * -12.000, + KCAL_TO_KJ * -7.0, + 1. / (ANG_TO_NM * 6.0), + 0.185, + } + }, + { "NY", { + ANG3_TO_NM3 * 12.001, + KCAL_TO_KJ * -5.950, + KCAL_TO_KJ * -5.950, + KCAL_TO_KJ * -9.059, + KCAL_TO_KJ * -8.8, + 1. / (ANG_TO_NM * 3.5), + 0.185, + } + }, + { "NP", { + ANG3_TO_NM3 * 4.993, + KCAL_TO_KJ * -20.000, + KCAL_TO_KJ * -20.000, + KCAL_TO_KJ * -25.000, + KCAL_TO_KJ * -18.0, + 1. / (ANG_TO_NM * 6.0), + 0.185, + } + }, + { "O", { + ANG3_TO_NM3 * 11.772, + KCAL_TO_KJ * -5.330, + KCAL_TO_KJ * -5.330, + KCAL_TO_KJ * -5.787, + KCAL_TO_KJ * -8.8, + 1. / (ANG_TO_NM * 3.5), + 0.170, + } + }, + { "OB", { + ANG3_TO_NM3 * 11.694, + KCAL_TO_KJ * -5.330, + KCAL_TO_KJ * -5.330, + KCAL_TO_KJ * -5.787, + KCAL_TO_KJ * -8.8, + 1. / (ANG_TO_NM * 3.5), + 0.170, + } + }, + { "OC", { + ANG3_TO_NM3 * 12.003, + KCAL_TO_KJ * -10.000, + KCAL_TO_KJ * -10.000, + KCAL_TO_KJ * -12.000, + KCAL_TO_KJ * -9.4, + 1. / (ANG_TO_NM * 6.0), + 0.170, + } + }, + { "OH1", { + ANG3_TO_NM3 * 15.528, + KCAL_TO_KJ * -5.920, + KCAL_TO_KJ * -5.920, + KCAL_TO_KJ * -9.264, + KCAL_TO_KJ * -11.2, + 1. / (ANG_TO_NM * 3.5), + 0.177, + } + }, + { "OS", { + ANG3_TO_NM3 * 6.774, + KCAL_TO_KJ * -2.900, + KCAL_TO_KJ * -2.900, + KCAL_TO_KJ * -3.150, + KCAL_TO_KJ * -4.8, + 1. / (ANG_TO_NM * 3.5), + 0.177, + } + }, + { "S", { + ANG3_TO_NM3 * 20.703, + KCAL_TO_KJ * -3.240, + KCAL_TO_KJ * -3.240, + KCAL_TO_KJ * -4.475, + KCAL_TO_KJ * -39.9, + 1. / (ANG_TO_NM * 3.5), + 0.20, + } + }, + { "SM", { + ANG3_TO_NM3 * 21.306, + KCAL_TO_KJ * -3.240, + KCAL_TO_KJ * -3.240, + KCAL_TO_KJ * -4.475, + KCAL_TO_KJ * -39.9, + 1. / (ANG_TO_NM * 3.5), + 0.197, + } } + }; + return valuemap; +} +} } diff --git a/src/colvar/Jcoupling.cpp b/src/colvar/Jcoupling.cpp index d7fda854c..d192b8bbd 100644 --- a/src/colvar/Jcoupling.cpp +++ b/src/colvar/Jcoupling.cpp @@ -29,8 +29,8 @@ using namespace std; -namespace PLMD{ - namespace colvar{ +namespace PLMD { +namespace colvar { //+PLUMEDOC COLVAR JCOUPLING /* @@ -90,242 +90,242 @@ ENDPLUMED */ //+ENDPLUMEDOC - class JCoupling : public Colvar { - private: - bool pbc; - vector<double> coupl; - unsigned ndata; - unsigned jtype_; - enum { HAN, HAHN, CCG, NCG, CUSTOM }; - double ka_; - double kb_; - double kc_; - double kshift_; - - public: - explicit JCoupling(const ActionOptions&); - virtual void calculate(); - static void registerKeywords(Keywords& keys); - }; - - PLUMED_REGISTER_ACTION(JCoupling, "JCOUPLING") - - void JCoupling::registerKeywords(Keywords& keys) { - Colvar::registerKeywords(keys); - componentsAreNotOptional(keys); - useCustomisableComponents(keys); - keys.add("numbered", "ATOMS", "the 4 atoms involved in each of the bonds for which you wish to calculate the J-coupling. " - "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one J-coupling will be " - "calculated for each ATOMS keyword you specify."); - keys.reset_style("ATOMS", "atoms"); - keys.addFlag("ADDCOUPLINGS", false, "Set this flag if you want to have fixed components with the experimental values."); - keys.add("compulsory", "TYPE", "Type of J-coupling to compute (HAN,HAHN,CCG,NCG,CUSTOM)"); - keys.add("optional", "A", "Karplus parameter A"); - keys.add("optional", "B", "Karplus parameter B"); - keys.add("optional", "C", "Karplus parameter C"); - keys.add("optional", "SHIFT", "Angle shift in radians"); - keys.add("numbered", "COUPLING", "Add an experimental value for each coupling"); - keys.addOutputComponent("j", "default", "the calculated J-coupling"); - keys.addOutputComponent("exp", "ADDCOUPLINGS", "the experimental J-coupling"); - } - - JCoupling::JCoupling(const ActionOptions&ao): - PLUMED_COLVAR_INIT(ao), - pbc(true), - ndata(0) - { - bool nopbc = !pbc; - parseFlag("NOPBC", nopbc); - pbc =! nopbc; - - // Read in the atoms - vector<AtomNumber> t, atoms; - for (int i = 1; ; ++i) { - parseAtomList("ATOMS", i, t ); - if (t.empty()) { - break; - } - - if (t.size() != 4) { - std::string ss; - Tools::convert(i, ss); - error("ATOMS" + ss + " keyword has the wrong number of atoms"); - } - - // This makes the distance calculation easier later on (see Torsion implementation) - atoms.push_back(t[0]); - atoms.push_back(t[1]); - atoms.push_back(t[1]); - atoms.push_back(t[2]); - atoms.push_back(t[2]); - atoms.push_back(t[3]); - t.resize(0); - } - - // We now have 6 atoms per datapoint - ndata = atoms.size()/6; - - // Parse J-Coupling type, this will determine the Karplus parameters - string string_type; - parse("TYPE", string_type); - if(string_type == "HAN") { - jtype_ = HAN; - } else if(string_type == "HAHN") { - jtype_ = HAHN; - } else if(string_type == "CCG") { - jtype_ = CCG; - } else if(string_type == "NCG") { - jtype_ = NCG; - } else if(string_type == "CUSTOM") { - jtype_ = CUSTOM; - } else { - error("Unknown J-coupling type!"); - } - - // Optionally add an experimental value (like with RDCs) - bool addcoupling = false; - parseFlag("ADDCOUPLINGS", addcoupling); - if (addcoupling) { - coupl.resize(ndata); - unsigned ntarget = 0; - for (unsigned i = 0; i < ndata; ++i) { - if (!parseNumbered("COUPLING", i+1, coupl[i])){ - break; - } - ntarget++; - } - if (ntarget != ndata) { - error("found wrong number of COUPLING values"); - } - } - - // For custom types we allow use of custom Karplus parameters - if (jtype_ == CUSTOM) { - parse("A", ka_); - parse("B", kb_); - parse("C", kc_); - parse("SHIFT", kshift_); - } - - checkRead(); - - // Set Karplus parameters - switch (jtype_) { - case HAN: - ka_ = -0.88; - kb_ = -0.61; - kc_ = -0.27; - kshift_ = pi / 3.0; - log.printf("J-coupling type is HAN, with A: %f, B: %f, C: %f, angle shift: %f\n", ka_, kb_, kc_, kshift_); - log << " Bibliography " - << plumed.cite("Wang A C, Bax A, J. Am. Chem. Soc. 117, 1810 (1995)") << "\n"; - break; - case HAHN: - ka_ = 7.09; - kb_ = -1.42; - kc_ = 1.55; - kshift_ = -pi / 3.0; - log.printf("J-coupling type is HAHN, with A: %f, B: %f, C: %f, angle shift: %f\n", ka_, kb_, kc_, kshift_); - log << " Bibliography " - << plumed.cite("Hu J-S, Bax A, J. Am. Chem. Soc. 119, 6360 (1997)") << "\n"; - break; - case CCG: - ka_ = 2.31; - kb_ = -0.87; - kc_ = 0.55; - kshift_ = (2.0 * pi) / 3.0; - log.printf("J-coupling type is CCG, with A: %f, B: %f, C: %f, angle shift: %f\n", ka_, kb_, kc_, kshift_); - log << " Bibliography " - << plumed.cite("Perez C, Löhr F, Rüterjans H, Schmidt J, J. Am. Chem. Soc. 123, 7081 (2001)") << "\n"; - break; - case NCG: - ka_ = 1.29; - kb_ = -0.49; - kc_ = 0.37; - kshift_ = 0.0; - log.printf("J-coupling type is NCG, with A: %f, B: %f, C: %f, angle shift: %f\n", ka_, kb_, kc_, kshift_); - log << " Bibliography " - << plumed.cite("Perez C, Löhr F, Rüterjans H, Schmidt J, J. Am. Chem. Soc. 123, 7081 (2001)") << "\n"; - break; - case CUSTOM: - log.printf("J-coupling type is custom, with A: %f, B: %f, C: %f, angle shift: %f\n", ka_, kb_, kc_, kshift_); - break; - } - - for (unsigned i = 0; i < ndata; ++i) { - log.printf(" The %uth J-Coupling is calculated from atoms : %d %d %d %d.", - i+1, atoms[2*i].serial(), atoms[2*i+1].serial(), atoms[2*i+2].serial(), atoms[2*i+3].serial()); - if (addcoupling) { - log.printf(" Experimental J-Coupling is %f.", coupl[i]); - } - log.printf("\n"); - } - - if (pbc) { - log.printf(" using periodic boundary conditions\n"); - } else { - log.printf(" without periodic boundary conditions\n"); - } - - for (unsigned i = 0; i < ndata; i++) { - std::string num; Tools::convert(i, num); - addComponentWithDerivatives("j_" + num); - componentIsNotPeriodic("j_" + num); - } - - if (addcoupling) { - for (unsigned i = 0; i < ndata; i++) { - std::string num; Tools::convert(i, num); - addComponent("exp_" + num); - componentIsNotPeriodic("exp_" + num); - Value* comp = getPntrToComponent("exp_" + num); - comp->set(coupl[i]); - } - } - - requestAtoms(atoms); - } - - void JCoupling::calculate() { - if (pbc) { - makeWhole(); - } - - // Loop through atoms, with steps of 6 atoms (one iteration per datapoint) - for (unsigned r = 0; r < (ndata * 6); r += 6) { - // Index is the datapoint index - const unsigned index = r / 6; - - // 6 atoms -> 3 vectors - Vector d0, d1, d2; - d0 = delta(getPosition(r + 1), getPosition(r + 0)); - d1 = delta(getPosition(r + 3), getPosition(r + 2)); - d2 = delta(getPosition(r + 5), getPosition(r + 4)); - - // Calculate dihedral with 3 vectors, get the derivatives - Vector dd0, dd1, dd2; - PLMD::Torsion t; - const double torsion = t.compute(d0, d1, d2, dd0, dd1, dd2); - - // Calculate the Karplus relation and its derivative - const double theta = torsion + kshift_; - const double cos_theta = cos(theta); - const double j = ka_ * cos_theta * cos_theta + kb_ * cos_theta + kc_; - const double derj = sin(theta) * (-1.0 * (2.0 * ka_ * cos_theta + kb_)); - - Value* val = getPntrToComponent(index); - val->set(j); - - setAtomsDerivatives(val, r + 0, derj * dd0); - setAtomsDerivatives(val, r + 1, derj * -dd0); - setAtomsDerivatives(val, r + 2, derj * dd1); - setAtomsDerivatives(val, r + 3, derj * -dd1); - setAtomsDerivatives(val, r + 4, derj * dd2); - setAtomsDerivatives(val, r + 5, derj * -dd2); - setBoxDerivativesNoPbc(val); - } - } +class JCoupling : public Colvar { +private: + bool pbc; + vector<double> coupl; + unsigned ndata; + unsigned jtype_; + enum { HAN, HAHN, CCG, NCG, CUSTOM }; + double ka_; + double kb_; + double kc_; + double kshift_; + +public: + explicit JCoupling(const ActionOptions&); + virtual void calculate(); + static void registerKeywords(Keywords& keys); +}; + +PLUMED_REGISTER_ACTION(JCoupling, "JCOUPLING") + +void JCoupling::registerKeywords(Keywords& keys) { + Colvar::registerKeywords(keys); + componentsAreNotOptional(keys); + useCustomisableComponents(keys); + keys.add("numbered", "ATOMS", "the 4 atoms involved in each of the bonds for which you wish to calculate the J-coupling. " + "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one J-coupling will be " + "calculated for each ATOMS keyword you specify."); + keys.reset_style("ATOMS", "atoms"); + keys.addFlag("ADDCOUPLINGS", false, "Set this flag if you want to have fixed components with the experimental values."); + keys.add("compulsory", "TYPE", "Type of J-coupling to compute (HAN,HAHN,CCG,NCG,CUSTOM)"); + keys.add("optional", "A", "Karplus parameter A"); + keys.add("optional", "B", "Karplus parameter B"); + keys.add("optional", "C", "Karplus parameter C"); + keys.add("optional", "SHIFT", "Angle shift in radians"); + keys.add("numbered", "COUPLING", "Add an experimental value for each coupling"); + keys.addOutputComponent("j", "default", "the calculated J-coupling"); + keys.addOutputComponent("exp", "ADDCOUPLINGS", "the experimental J-coupling"); +} + +JCoupling::JCoupling(const ActionOptions&ao): + PLUMED_COLVAR_INIT(ao), + pbc(true), + ndata(0) +{ + bool nopbc = !pbc; + parseFlag("NOPBC", nopbc); + pbc =! nopbc; + + // Read in the atoms + vector<AtomNumber> t, atoms; + for (int i = 1; ; ++i) { + parseAtomList("ATOMS", i, t ); + if (t.empty()) { + break; + } + + if (t.size() != 4) { + std::string ss; + Tools::convert(i, ss); + error("ATOMS" + ss + " keyword has the wrong number of atoms"); + } + + // This makes the distance calculation easier later on (see Torsion implementation) + atoms.push_back(t[0]); + atoms.push_back(t[1]); + atoms.push_back(t[1]); + atoms.push_back(t[2]); + atoms.push_back(t[2]); + atoms.push_back(t[3]); + t.resize(0); + } + + // We now have 6 atoms per datapoint + ndata = atoms.size()/6; + + // Parse J-Coupling type, this will determine the Karplus parameters + string string_type; + parse("TYPE", string_type); + if(string_type == "HAN") { + jtype_ = HAN; + } else if(string_type == "HAHN") { + jtype_ = HAHN; + } else if(string_type == "CCG") { + jtype_ = CCG; + } else if(string_type == "NCG") { + jtype_ = NCG; + } else if(string_type == "CUSTOM") { + jtype_ = CUSTOM; + } else { + error("Unknown J-coupling type!"); + } + + // Optionally add an experimental value (like with RDCs) + bool addcoupling = false; + parseFlag("ADDCOUPLINGS", addcoupling); + if (addcoupling) { + coupl.resize(ndata); + unsigned ntarget = 0; + for (unsigned i = 0; i < ndata; ++i) { + if (!parseNumbered("COUPLING", i+1, coupl[i])) { + break; + } + ntarget++; + } + if (ntarget != ndata) { + error("found wrong number of COUPLING values"); } + } + + // For custom types we allow use of custom Karplus parameters + if (jtype_ == CUSTOM) { + parse("A", ka_); + parse("B", kb_); + parse("C", kc_); + parse("SHIFT", kshift_); + } + + checkRead(); + + // Set Karplus parameters + switch (jtype_) { + case HAN: + ka_ = -0.88; + kb_ = -0.61; + kc_ = -0.27; + kshift_ = pi / 3.0; + log.printf("J-coupling type is HAN, with A: %f, B: %f, C: %f, angle shift: %f\n", ka_, kb_, kc_, kshift_); + log << " Bibliography " + << plumed.cite("Wang A C, Bax A, J. Am. Chem. Soc. 117, 1810 (1995)") << "\n"; + break; + case HAHN: + ka_ = 7.09; + kb_ = -1.42; + kc_ = 1.55; + kshift_ = -pi / 3.0; + log.printf("J-coupling type is HAHN, with A: %f, B: %f, C: %f, angle shift: %f\n", ka_, kb_, kc_, kshift_); + log << " Bibliography " + << plumed.cite("Hu J-S, Bax A, J. Am. Chem. Soc. 119, 6360 (1997)") << "\n"; + break; + case CCG: + ka_ = 2.31; + kb_ = -0.87; + kc_ = 0.55; + kshift_ = (2.0 * pi) / 3.0; + log.printf("J-coupling type is CCG, with A: %f, B: %f, C: %f, angle shift: %f\n", ka_, kb_, kc_, kshift_); + log << " Bibliography " + << plumed.cite("Perez C, Löhr F, Rüterjans H, Schmidt J, J. Am. Chem. Soc. 123, 7081 (2001)") << "\n"; + break; + case NCG: + ka_ = 1.29; + kb_ = -0.49; + kc_ = 0.37; + kshift_ = 0.0; + log.printf("J-coupling type is NCG, with A: %f, B: %f, C: %f, angle shift: %f\n", ka_, kb_, kc_, kshift_); + log << " Bibliography " + << plumed.cite("Perez C, Löhr F, Rüterjans H, Schmidt J, J. Am. Chem. Soc. 123, 7081 (2001)") << "\n"; + break; + case CUSTOM: + log.printf("J-coupling type is custom, with A: %f, B: %f, C: %f, angle shift: %f\n", ka_, kb_, kc_, kshift_); + break; + } + + for (unsigned i = 0; i < ndata; ++i) { + log.printf(" The %uth J-Coupling is calculated from atoms : %d %d %d %d.", + i+1, atoms[2*i].serial(), atoms[2*i+1].serial(), atoms[2*i+2].serial(), atoms[2*i+3].serial()); + if (addcoupling) { + log.printf(" Experimental J-Coupling is %f.", coupl[i]); + } + log.printf("\n"); + } + + if (pbc) { + log.printf(" using periodic boundary conditions\n"); + } else { + log.printf(" without periodic boundary conditions\n"); + } + + for (unsigned i = 0; i < ndata; i++) { + std::string num; Tools::convert(i, num); + addComponentWithDerivatives("j_" + num); + componentIsNotPeriodic("j_" + num); + } + + if (addcoupling) { + for (unsigned i = 0; i < ndata; i++) { + std::string num; Tools::convert(i, num); + addComponent("exp_" + num); + componentIsNotPeriodic("exp_" + num); + Value* comp = getPntrToComponent("exp_" + num); + comp->set(coupl[i]); + } + } + + requestAtoms(atoms); +} + +void JCoupling::calculate() { + if (pbc) { + makeWhole(); + } + + // Loop through atoms, with steps of 6 atoms (one iteration per datapoint) + for (unsigned r = 0; r < (ndata * 6); r += 6) { + // Index is the datapoint index + const unsigned index = r / 6; + + // 6 atoms -> 3 vectors + Vector d0, d1, d2; + d0 = delta(getPosition(r + 1), getPosition(r + 0)); + d1 = delta(getPosition(r + 3), getPosition(r + 2)); + d2 = delta(getPosition(r + 5), getPosition(r + 4)); + + // Calculate dihedral with 3 vectors, get the derivatives + Vector dd0, dd1, dd2; + PLMD::Torsion t; + const double torsion = t.compute(d0, d1, d2, dd0, dd1, dd2); + + // Calculate the Karplus relation and its derivative + const double theta = torsion + kshift_; + const double cos_theta = cos(theta); + const double j = ka_ * cos_theta * cos_theta + kb_ * cos_theta + kc_; + const double derj = sin(theta) * (-1.0 * (2.0 * ka_ * cos_theta + kb_)); + + Value* val = getPntrToComponent(index); + val->set(j); + + setAtomsDerivatives(val, r + 0, derj * dd0); + setAtomsDerivatives(val, r + 1, derj * -dd0); + setAtomsDerivatives(val, r + 2, derj * dd1); + setAtomsDerivatives(val, r + 3, derj * -dd1); + setAtomsDerivatives(val, r + 4, derj * dd2); + setAtomsDerivatives(val, r + 5, derj * -dd2); + setBoxDerivativesNoPbc(val); + } +} +} } diff --git a/src/colvar/MultiRMSD.cpp b/src/colvar/MultiRMSD.cpp index 72e62b945..7656c232b 100644 --- a/src/colvar/MultiRMSD.cpp +++ b/src/colvar/MultiRMSD.cpp @@ -30,13 +30,13 @@ using namespace std; -namespace PLMD{ -namespace colvar{ - +namespace PLMD { +namespace colvar { + class MultiRMSD : public Colvar { - + PLMD::MultiDomainRMSD* rmsd; - bool squared; + bool squared; MultiValue myvals; ReferenceValuePack mypack; @@ -52,11 +52,11 @@ using namespace std; //+PLUMEDOC DCOLVAR MULTI-RMSD /* -Calculate the RMSD distance moved by a number of separated domains from their positions in a reference structure. +Calculate the RMSD distance moved by a number of separated domains from their positions in a reference structure. When you have large proteins the calculation of the root mean squared deviation between all the atoms in a reference -structure and the instantaneous configuration becomes prohibitively expensive. You may thus instead want to calculate +structure and the instantaneous configuration becomes prohibitively expensive. You may thus instead want to calculate the RMSD between the atoms in a set of domains of your protein and your reference structure. That is to say: \f[ @@ -64,7 +64,7 @@ d(X,X_r) = \sqrt{ \sum_{i} w_i\vert X_i - X_i' \vert^2 } \f] where here the sum is over the domains of the protein, \f$X_i\f$ represents the positions of the atoms in domain \f$i\f$ -in the instantaneous configuration and \f$X_i'\f$ is the positions of the atoms in domain \f$i\f$ in the reference +in the instantaneous configuration and \f$X_i'\f$ is the positions of the atoms in domain \f$i\f$ in the reference configuration. \f$w_i\f$ is an optional weight. The distances for each of the domains in the above sum can be calculated using the \ref DRMSD or \ref RMSD measures or @@ -109,7 +109,7 @@ positions. Here distances are calculated using the \ref DRMSD measure. \verbatim MULTI-RMSD REFERENCE=file.pdb TYPE=MULTI-DRMSD -\endverbatim +\endverbatim in this case it is possible to use the following DRMSD options in the pdb file using the REMARK syntax: \verbatim @@ -117,7 +117,7 @@ NOPBC to calculate distances without PBC LOWER_CUTOFF=# only pairs of atoms further than LOWER_CUTOFF are considered in the calculation UPPER_CUTOFF=# only pairs of atoms further than UPPER_CUTOFF are considered in the calculation \endverbatim -as shown in the following example +as shown in the following example \verbatim REMARK NOPBC @@ -141,14 +141,14 @@ ATOM 21 HB2 ALA 2 2.556 -1.051 -0.295 1.00 1.00 DIA H ATOM 22 HB3 ALA 2 2.070 -2.314 -1.490 1.00 1.00 DIA H END \endverbatim - + */ //+ENDPLUMEDOC PLUMED_REGISTER_ACTION(MultiRMSD,"MULTI-RMSD") -void MultiRMSD::registerKeywords(Keywords& keys){ +void MultiRMSD::registerKeywords(Keywords& keys) { Colvar::registerKeywords(keys); keys.add("compulsory","REFERENCE","a file in pdb format containing the reference structure and the atoms involved in the CV."); keys.add("compulsory","TYPE","MULTI-SIMPLE","the manner in which RMSD alignment is performed. Should be MULTI-OPTIMAL, MULTI-OPTIMAL-FAST, MULTI-SIMPLE or MULTI-DRMSD."); @@ -157,11 +157,11 @@ void MultiRMSD::registerKeywords(Keywords& keys){ } MultiRMSD::MultiRMSD(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao),squared(false),myvals(1,0), mypack(0,0,myvals) + PLUMED_COLVAR_INIT(ao),squared(false),myvals(1,0), mypack(0,0,myvals) { string reference; parse("REFERENCE",reference); - string type; + string type; type.assign("SIMPLE"); parse("TYPE",type); parseFlag("SQUARED",squared); @@ -174,16 +174,16 @@ PLUMED_COLVAR_INIT(ao),squared(false),myvals(1,0), mypack(0,0,myvals) // read everything in ang and transform to nm if we are not in natural units if( !pdb.read(reference,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength()) ) - error("missing input file " + reference ); + error("missing input file " + reference ); rmsd = metricRegister().create<MultiDomainRMSD>(type,pdb); - + std::vector<AtomNumber> atoms; rmsd->getAtomRequests( atoms ); requestAtoms( atoms ); myvals.resize( 1, 3*atoms.size()+9 ); mypack.resize( 0, atoms.size() ); - for(unsigned i=0;i<atoms.size();++i) mypack.setAtomIndex( i, i ); + for(unsigned i=0; i<atoms.size(); ++i) mypack.setAtomIndex( i, i ); log.printf(" reference from file %s\n",reference.c_str()); log.printf(" which contains %d atoms\n",getNumberOfAtoms()); @@ -191,17 +191,17 @@ PLUMED_COLVAR_INIT(ao),squared(false),myvals(1,0), mypack(0,0,myvals) if(squared)log.printf(" chosen to use SQUARED option for MSD instead of RMSD\n"); } -MultiRMSD::~MultiRMSD(){ +MultiRMSD::~MultiRMSD() { delete rmsd; } // calculator -void MultiRMSD::calculate(){ +void MultiRMSD::calculate() { double r=rmsd->calculate( getPositions(), getPbc(), mypack, squared ); - setValue(r); - for(unsigned i=0;i<getNumberOfAtoms();i++) setAtomsDerivatives( i, mypack.getAtomDerivative(i) ); + setValue(r); + for(unsigned i=0; i<getNumberOfAtoms(); i++) setAtomsDerivatives( i, mypack.getAtomDerivative(i) ); if( !mypack.virialWasSet() ) setBoxDerivativesNoPbc(); else setBoxDerivatives( mypack.getBoxDerivatives() ); diff --git a/src/colvar/NOE.cpp b/src/colvar/NOE.cpp index 98ed26eaf..82d2b4372 100644 --- a/src/colvar/NOE.cpp +++ b/src/colvar/NOE.cpp @@ -32,7 +32,7 @@ using namespace std; namespace PLMD { namespace colvar { -//+PLUMEDOC COLVAR NOE +//+PLUMEDOC COLVAR NOE /* Calculates NOE intensities as sums of 1/r^6, also averaging over multiple equivalent atoms or ambiguous NOE. @@ -41,7 +41,7 @@ Each NOE is defined by two groups containing the same number of atoms, distances calculated in pairs, transformed in 1/r^6, summed and saved as components. \f[ -NOE() = (\frac{1}{N_{eq}}\sum_j^{N_{eq}} (\frac{1}{r_j^6}))^{\frac{-1}{6}} +NOE() = (\frac{1}{N_{eq}}\sum_j^{N_{eq}} (\frac{1}{r_j^6}))^{\frac{-1}{6}} \f] Intensities can then in principle ensemble averaged using \ref ENSEMBLE and used to @@ -54,7 +54,7 @@ of atom 1-2 and 3-2; the second is defined by the distance 5-7 and the third by \verbatim NOE ... -GROUPA1=1,3 GROUPB1=2,2 +GROUPA1=1,3 GROUPB1=2,2 GROUPA2=5 GROUPB2=7 GROUPA3=4,4,8,8 GROUPB3=15,16,15,16 LABEL=noes @@ -62,12 +62,12 @@ LABEL=noes PRINT ARG=noes.* FILE=colvar \endverbatim -(See also \ref PRINT) +(See also \ref PRINT) */ //+ENDPLUMEDOC -class NOE : public Colvar { +class NOE : public Colvar { private: bool pbc; vector<unsigned> nga; @@ -81,49 +81,49 @@ public: PLUMED_REGISTER_ACTION(NOE,"NOE") -void NOE::registerKeywords( Keywords& keys ){ +void NOE::registerKeywords( Keywords& keys ) { Colvar::registerKeywords( keys ); componentsAreNotOptional(keys); useCustomisableComponents(keys); keys.add("numbered","GROUPA","the atoms involved in each of the contacts you wish to calculate. " - "Keywords like GROUPA1, GROUPA2, GROUPA3,... should be listed and one contact will be " - "calculated for each ATOM keyword you specify."); + "Keywords like GROUPA1, GROUPA2, GROUPA3,... should be listed and one contact will be " + "calculated for each ATOM keyword you specify."); keys.add("numbered","GROUPB","the atoms involved in each of the contacts you wish to calculate. " - "Keywords like GROUPB1, GROUPB2, GROUPB3,... should be listed and one contact will be " - "calculated for each ATOM keyword you specify."); + "Keywords like GROUPB1, GROUPB2, GROUPB3,... should be listed and one contact will be " + "calculated for each ATOM keyword you specify."); keys.reset_style("GROUPA","atoms"); keys.reset_style("GROUPB","atoms"); - keys.addFlag("ADDEXP",false,"Set to TRUE if you want to have fixed components with the experimental reference values."); + keys.addFlag("ADDEXP",false,"Set to TRUE if you want to have fixed components with the experimental reference values."); keys.add("numbered","NOEDIST","Add an experimental value for each NOE."); keys.addOutputComponent("noe","default","the # NOE"); keys.addOutputComponent("exp","ADDEXP","the # NOE experimental distance"); } NOE::NOE(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao), -pbc(true) + PLUMED_COLVAR_INIT(ao), + pbc(true) { bool nopbc=!pbc; parseFlag("NOPBC",nopbc); - pbc=!nopbc; + pbc=!nopbc; // Read in the atoms vector<AtomNumber> t, ga_lista, gb_lista; - for(int i=1;;++i ){ - parseAtomList("GROUPA", i, t ); - if( t.empty() ) break; - for(unsigned j=0;j<t.size();j++) ga_lista.push_back(t[j]); - nga.push_back(t.size()); - t.resize(0); + for(int i=1;; ++i ) { + parseAtomList("GROUPA", i, t ); + if( t.empty() ) break; + for(unsigned j=0; j<t.size(); j++) ga_lista.push_back(t[j]); + nga.push_back(t.size()); + t.resize(0); } vector<unsigned> ngb; - for(int i=1;;++i ){ - parseAtomList("GROUPB", i, t ); - if( t.empty() ) break; - for(unsigned j=0;j<t.size();j++) gb_lista.push_back(t[j]); - ngb.push_back(t.size()); - if(ngb[i-1]!=nga[i-1]) error("The same number of atoms is expected for the same GROUPA-GROUPB couple"); - t.resize(0); + for(int i=1;; ++i ) { + parseAtomList("GROUPB", i, t ); + if( t.empty() ) break; + for(unsigned j=0; j<t.size(); j++) gb_lista.push_back(t[j]); + ngb.push_back(t.size()); + if(ngb[i-1]!=nga[i-1]) error("The same number of atoms is expected for the same GROUPA-GROUPB couple"); + t.resize(0); } if(nga.size()!=ngb.size()) error("There should be the same number of GROUPA and GROUPB keywords"); // Create neighbour lists @@ -134,21 +134,21 @@ pbc(true) vector<double> noedist; if(addexp) { - noedist.resize( nga.size() ); + noedist.resize( nga.size() ); unsigned ntarget=0; - for(unsigned i=0;i<nga.size();++i){ - if( !parseNumbered( "NOEDIST", i+1, noedist[i] ) ) break; - ntarget++; + for(unsigned i=0; i<nga.size(); ++i) { + if( !parseNumbered( "NOEDIST", i+1, noedist[i] ) ) break; + ntarget++; } if( ntarget!=nga.size() ) error("found wrong number of NOEDIST values"); } // Ouput details of all contacts - unsigned index=0; - for(unsigned i=0;i<nga.size();++i){ + unsigned index=0; + for(unsigned i=0; i<nga.size(); ++i) { log.printf(" The %uth NOE is calculated using %u equivalent couples of atoms\n", i, nga[i]); - for(unsigned j=0;j<nga[i];j++) { + for(unsigned j=0; j<nga[i]; j++) { log.printf(" couple %u is %d %d.\n", j, ga_lista[index].serial(), gb_lista[index].serial() ); index++; } @@ -157,14 +157,14 @@ pbc(true) if(pbc) log.printf(" using periodic boundary conditions\n"); else log.printf(" without periodic boundary conditions\n"); - for(unsigned i=0;i<nga.size();i++) { + for(unsigned i=0; i<nga.size(); i++) { string num; Tools::convert(i,num); addComponentWithDerivatives("noe_"+num); componentIsNotPeriodic("noe_"+num); } if(addexp) { - for(unsigned i=0;i<nga.size();i++) { + for(unsigned i=0; i<nga.size(); i++) { string num; Tools::convert(i,num); addComponent("exp_"+num); componentIsNotPeriodic("exp_"+num); @@ -177,24 +177,24 @@ pbc(true) checkRead(); } -NOE::~NOE(){ +NOE::~NOE() { delete nl; -} +} void NOE::calculate() { const unsigned ngasz=nga.size(); - #pragma omp parallel for num_threads(OpenMP::getNumThreads()) - for(unsigned i=0;i<ngasz;i++) { + #pragma omp parallel for num_threads(OpenMP::getNumThreads()) + for(unsigned i=0; i<ngasz; i++) { Tensor dervir; double noe=0; unsigned index=0; - for(unsigned k=0; k<i; k++) index+=nga[k]; + for(unsigned k=0; k<i; k++) index+=nga[k]; const double c_aver=1./static_cast<double>(nga[i]); Value* val=getPntrToComponent(i); - // cycle over equivalent atoms - for(unsigned j=0;j<nga[i];j++) { + // cycle over equivalent atoms + for(unsigned j=0; j<nga[i]; j++) { const unsigned i0=nl->getClosePair(index+j).first; const unsigned i1=nl->getClosePair(index+j).second; diff --git a/src/colvar/PCARMSD.cpp b/src/colvar/PCARMSD.cpp index 3e1688e90..f5d1cf6f2 100644 --- a/src/colvar/PCARMSD.cpp +++ b/src/colvar/PCARMSD.cpp @@ -29,13 +29,13 @@ using namespace std; -namespace PLMD{ -namespace colvar{ - +namespace PLMD { +namespace colvar { + class PCARMSD : public Colvar { - + PLMD::RMSD* rmsd; - bool squared; + bool squared; std::vector< std::vector<Vector> > eigenvectors; std::vector<PDB> pdbv; std::vector<string> pca_names; @@ -49,7 +49,7 @@ public: using namespace std; -//+PLUMEDOC DCOLVAR PCARMSD +//+PLUMEDOC DCOLVAR PCARMSD /* Calculate the PCA components ( see \cite Sutto:2010 and \cite spiwok ) for a number of provided eigenvectors and an average structure. Performs optimal alignment at every step and reports the rmsd so you know if you are far or close from the average structure. It takes the average structure and eigenvectors in form of a pdb. @@ -58,17 +58,17 @@ Note that beta and occupancy values in the pdb are neglected and all the weights \par Examples \verbatim -PCARMSD AVERAGE=file.pdb EIGENVECTORS=eigenvectors.pdb +PCARMSD AVERAGE=file.pdb EIGENVECTORS=eigenvectors.pdb \endverbatim -The input is taken so to be compatible with the output you get from g_covar utility of gromacs (suitably adapted to have a pdb input format). +The input is taken so to be compatible with the output you get from g_covar utility of gromacs (suitably adapted to have a pdb input format). */ //+ENDPLUMEDOC PLUMED_REGISTER_ACTION(PCARMSD,"PCARMSD") -void PCARMSD::registerKeywords(Keywords& keys){ +void PCARMSD::registerKeywords(Keywords& keys) { Colvar::registerKeywords(keys); keys.add("compulsory","AVERAGE","a file in pdb format containing the reference structure and the atoms involved in the CV."); keys.add("compulsory","EIGENVECTORS","a file in pdb format containing the reference structure and the atoms involved in the CV."); @@ -79,35 +79,35 @@ void PCARMSD::registerKeywords(Keywords& keys){ } PCARMSD::PCARMSD(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao),squared(true) + PLUMED_COLVAR_INIT(ao),squared(true) { string f_average; parse("AVERAGE",f_average); - string type; + string type; type.assign("OPTIMAL"); string f_eigenvectors; parse("EIGENVECTORS",f_eigenvectors); bool sq; parseFlag("SQUARED-ROOT",sq); - if (sq){ squared=false; } + if (sq) { squared=false; } checkRead(); PDB pdb; // read everything in ang and transform to nm if we are not in natural units if( !pdb.read(f_average,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength()) ) - error("missing input file " + f_average ); + error("missing input file " + f_average ); rmsd = new RMSD(); bool remove_com=true; bool normalize_weights=true; // here align and displace are a simple vector of ones - std::vector<double> align; align=pdb.getOccupancy();for(unsigned i=0;i<align.size();i++){align[i]=1.;} ; - std::vector<double> displace; displace=pdb.getBeta();for(unsigned i=0;i<displace.size();i++){displace[i]=1.;} ; + std::vector<double> align; align=pdb.getOccupancy(); for(unsigned i=0; i<align.size(); i++) {align[i]=1.;} ; + std::vector<double> displace; displace=pdb.getBeta(); for(unsigned i=0; i<displace.size(); i++) {displace[i]=1.;} ; // reset again to reimpose unifrom weights (safe to disable this) rmsd->set(align,displace,pdb.getPositions(),type,remove_com,normalize_weights); requestAtoms( pdb.getAtomNumbers() ); - addComponentWithDerivatives("residual"); componentIsNotPeriodic("residual"); + addComponentWithDerivatives("residual"); componentIsNotPeriodic("residual"); log.printf(" average from file %s\n",f_average.c_str()); log.printf(" which contains %d atoms\n",getNumberOfAtoms()); @@ -116,7 +116,7 @@ PLUMED_COLVAR_INIT(ao),squared(true) log<<" Bibliography "<<plumed.cite("Spiwok, Lipovova and Kralova, JPCB, 111, 3073 (2007) "); log<<" "<<plumed.cite( "Sutto, D'Abramo, Gervasio, JCTC, 6, 3640 (2010)"); - // now get the eigenvectors + // now get the eigenvectors // open the file FILE* fp=fopen(f_eigenvectors.c_str(),"r"); std::vector<AtomNumber> aaa; @@ -126,94 +126,94 @@ PLUMED_COLVAR_INIT(ao),squared(true) { log<<" Opening the eigenvectors file "<<f_eigenvectors.c_str()<<"\n"; bool do_read=true; - while (do_read){ - PDB mypdb; - // check the units for reading this file: how can they make sense? - do_read=mypdb.readFromFilepointer(fp,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength()); - if(do_read){ - neigenvects++; - if(mypdb.getAtomNumbers().size()==0) error("number of atoms in a frame should be more than zero"); - unsigned nat=mypdb.getAtomNumbers().size(); - if(nat!=mypdb.getAtomNumbers().size()) error("frames should have the same number of atoms"); - if(aaa.empty()) aaa=mypdb.getAtomNumbers(); - if(aaa!=mypdb.getAtomNumbers()) error("frames should contain same atoms in same order"); - log<<" Found eigenvector: "<<neigenvects<<" containing "<<mypdb.getAtomNumbers().size()<<" atoms\n"; - pdbv.push_back(mypdb); - eigenvectors.push_back(mypdb.getPositions()); - }else{break ;} + while (do_read) { + PDB mypdb; + // check the units for reading this file: how can they make sense? + do_read=mypdb.readFromFilepointer(fp,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength()); + if(do_read) { + neigenvects++; + if(mypdb.getAtomNumbers().size()==0) error("number of atoms in a frame should be more than zero"); + unsigned nat=mypdb.getAtomNumbers().size(); + if(nat!=mypdb.getAtomNumbers().size()) error("frames should have the same number of atoms"); + if(aaa.empty()) aaa=mypdb.getAtomNumbers(); + if(aaa!=mypdb.getAtomNumbers()) error("frames should contain same atoms in same order"); + log<<" Found eigenvector: "<<neigenvects<<" containing "<<mypdb.getAtomNumbers().size()<<" atoms\n"; + pdbv.push_back(mypdb); + eigenvectors.push_back(mypdb.getPositions()); + } else {break ;} } fclose (fp); - log<<" Found total "<<neigenvects<< " eigenvectors in the file "<<f_eigenvectors.c_str()<<" \n"; + log<<" Found total "<<neigenvects<< " eigenvectors in the file "<<f_eigenvectors.c_str()<<" \n"; if(neigenvects==0) error("at least one eigenvector is expected"); - } - // the components - for(unsigned i=0;i<neigenvects;i++){ - std::string num; Tools::convert( i, num ); - string name; name=string("eig-")+num; - pca_names.push_back(name); - addComponentWithDerivatives(name); componentIsNotPeriodic(name); - } + } + // the components + for(unsigned i=0; i<neigenvects; i++) { + std::string num; Tools::convert( i, num ); + string name; name=string("eig-")+num; + pca_names.push_back(name); + addComponentWithDerivatives(name); componentIsNotPeriodic(name); + } turnOnDerivatives(); } -PCARMSD::~PCARMSD(){ +PCARMSD::~PCARMSD() { delete rmsd; } // calculator -void PCARMSD::calculate(){ - Tensor rotation,invrotation; - Matrix<std::vector<Vector> > drotdpos(3,3); - std::vector<Vector> alignedpos; - std::vector<Vector> centeredpos; - std::vector<Vector> centeredref; - std::vector<Vector> ddistdpos; - double r=rmsd->calc_PCAelements( getPositions(), ddistdpos, rotation , drotdpos , alignedpos ,centeredpos, centeredref ,squared); - invrotation=rotation.transpose(); - - Value* verr=getPntrToComponent("residual"); - verr->set(r); - for(unsigned iat=0;iat<getNumberOfAtoms();iat++){ - setAtomsDerivatives (verr,iat,ddistdpos[iat]); - } - - std::vector< Vector > der; - der.resize(getNumberOfAtoms()); - - - for(unsigned i=0;i<eigenvectors.size();i++){ - Value* value=getPntrToComponent(pca_names[i].c_str()); - double val;val=0.; - for(unsigned iat=0;iat<getNumberOfAtoms();iat++){ - val+=dotProduct(alignedpos[iat]-centeredref[iat],eigenvectors[i][iat]); der[iat].zero(); - } - value->set(val); - // here the loop is reversed to better suit the structure of the derivative of the rotation matrix - double tmp1; - for(unsigned a=0;a<3;a++){ - for(unsigned b=0;b<3;b++){ - tmp1=0.; - for(unsigned n=0;n<getNumberOfAtoms();n++){ - tmp1+=centeredpos[n][b]*eigenvectors[i][n][a]; - } - for(unsigned iat=0;iat<getNumberOfAtoms();iat++){ - der[iat]+=drotdpos[a][b][iat]*tmp1; - } - } - } - Vector v1; - for(unsigned n=0;n<getNumberOfAtoms();n++){ - v1+=(1./getNumberOfAtoms())*matmul(invrotation,eigenvectors[i][n]); - } - for(unsigned iat=0;iat<getNumberOfAtoms();iat++){ - der[iat]+=matmul(invrotation,eigenvectors[i][iat])-v1; - setAtomsDerivatives (value,iat,der[iat]); - } - } - - for(unsigned i=0;i<getNumberOfComponents();++i) setBoxDerivativesNoPbc( getPntrToComponent(i) ); +void PCARMSD::calculate() { + Tensor rotation,invrotation; + Matrix<std::vector<Vector> > drotdpos(3,3); + std::vector<Vector> alignedpos; + std::vector<Vector> centeredpos; + std::vector<Vector> centeredref; + std::vector<Vector> ddistdpos; + double r=rmsd->calc_PCAelements( getPositions(), ddistdpos, rotation, drotdpos, alignedpos,centeredpos, centeredref,squared); + invrotation=rotation.transpose(); + + Value* verr=getPntrToComponent("residual"); + verr->set(r); + for(unsigned iat=0; iat<getNumberOfAtoms(); iat++) { + setAtomsDerivatives (verr,iat,ddistdpos[iat]); + } + + std::vector< Vector > der; + der.resize(getNumberOfAtoms()); + + + for(unsigned i=0; i<eigenvectors.size(); i++) { + Value* value=getPntrToComponent(pca_names[i].c_str()); + double val; val=0.; + for(unsigned iat=0; iat<getNumberOfAtoms(); iat++) { + val+=dotProduct(alignedpos[iat]-centeredref[iat],eigenvectors[i][iat]); der[iat].zero(); + } + value->set(val); + // here the loop is reversed to better suit the structure of the derivative of the rotation matrix + double tmp1; + for(unsigned a=0; a<3; a++) { + for(unsigned b=0; b<3; b++) { + tmp1=0.; + for(unsigned n=0; n<getNumberOfAtoms(); n++) { + tmp1+=centeredpos[n][b]*eigenvectors[i][n][a]; + } + for(unsigned iat=0; iat<getNumberOfAtoms(); iat++) { + der[iat]+=drotdpos[a][b][iat]*tmp1; + } + } + } + Vector v1; + for(unsigned n=0; n<getNumberOfAtoms(); n++) { + v1+=(1./getNumberOfAtoms())*matmul(invrotation,eigenvectors[i][n]); + } + for(unsigned iat=0; iat<getNumberOfAtoms(); iat++) { + der[iat]+=matmul(invrotation,eigenvectors[i][iat])-v1; + setAtomsDerivatives (value,iat,der[iat]); + } + } + + for(unsigned i=0; i<getNumberOfComponents(); ++i) setBoxDerivativesNoPbc( getPntrToComponent(i) ); } diff --git a/src/colvar/PRE.cpp b/src/colvar/PRE.cpp index 3f671a554..906826b1f 100644 --- a/src/colvar/PRE.cpp +++ b/src/colvar/PRE.cpp @@ -32,7 +32,7 @@ using namespace std; namespace PLMD { namespace colvar { -//+PLUMEDOC COLVAR PRE +//+PLUMEDOC COLVAR PRE /* Calculates the Paramegnetic Resonance Enhancement intensity ratio between two atoms. The reference atom for the spin label is added with SPINLABEL, the affected atom(s) @@ -68,7 +68,7 @@ PRINT ARG=HN_pre.* FILE=PRE.dat STRIDE=1 */ //+ENDPLUMEDOC -class PRE : public Colvar { +class PRE : public Colvar { private: bool pbc; double constant, inept; @@ -84,7 +84,7 @@ public: PLUMED_REGISTER_ACTION(PRE,"PRE") -void PRE::registerKeywords( Keywords& keys ){ +void PRE::registerKeywords( Keywords& keys ) { Colvar::registerKeywords( keys ); componentsAreNotOptional(keys); useCustomisableComponents(keys); @@ -93,24 +93,24 @@ void PRE::registerKeywords( Keywords& keys ){ keys.add("compulsory","OMEGA","is the Larmor frequency of the nuclear spin (in MHz)."); keys.add("atoms","SPINLABEL","The atom to be used as the paramagnetic center."); keys.add("numbered","GROUPA","the atoms involved in each of the contacts you wish to calculate. " - "Keywords like GROUPA1, GROUPA2, GROUPA3,... should be listed and one contact will be " - "calculated for each ATOM keyword you specify."); + "Keywords like GROUPA1, GROUPA2, GROUPA3,... should be listed and one contact will be " + "calculated for each ATOM keyword you specify."); keys.reset_style("GROUPA","atoms"); keys.add("numbered","RTWO","The relaxation of the atom/atoms in the corresponding GROUPA of atoms. " - "Keywords like RTWO1, RTWO2, RTWO3,... should be listed."); - keys.addFlag("ADDEXP",false,"Set to TRUE if you want to have fixed components with the experimetnal values."); + "Keywords like RTWO1, RTWO2, RTWO3,... should be listed."); + keys.addFlag("ADDEXP",false,"Set to TRUE if you want to have fixed components with the experimetnal values."); keys.add("numbered","PREINT","Add an experimental value for each PRE."); keys.addOutputComponent("pre","default","the # PRE"); keys.addOutputComponent("exp","ADDEXP","the # PRE experimental intensity"); } PRE::PRE(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao), -pbc(true) + PLUMED_COLVAR_INIT(ao), + pbc(true) { bool nopbc=!pbc; parseFlag("NOPBC",nopbc); - pbc=!nopbc; + pbc=!nopbc; vector<AtomNumber> atom; parseAtomList("SPINLABEL",atom); @@ -118,24 +118,24 @@ pbc(true) // Read in the atoms vector<AtomNumber> t, ga_lista, gb_lista; - for(int i=1;;++i ){ - parseAtomList("GROUPA", i, t ); - if( t.empty() ) break; - for(unsigned j=0;j<t.size();j++) {ga_lista.push_back(t[j]); gb_lista.push_back(atom[0]);} - nga.push_back(t.size()); - t.resize(0); + for(int i=1;; ++i ) { + parseAtomList("GROUPA", i, t ); + if( t.empty() ) break; + for(unsigned j=0; j<t.size(); j++) {ga_lista.push_back(t[j]); gb_lista.push_back(atom[0]);} + nga.push_back(t.size()); + t.resize(0); } // Read in reference values - rtwo.resize( nga.size() ); + rtwo.resize( nga.size() ); unsigned ntarget=0; - for(unsigned i=0;i<nga.size();++i){ - if( !parseNumbered( "RTWO", i+1, rtwo[i] ) ) break; - ntarget++; + for(unsigned i=0; i<nga.size(); ++i) { + if( !parseNumbered( "RTWO", i+1, rtwo[i] ) ) break; + ntarget++; } - if( ntarget==0 ){ - parse("RTWO",rtwo[0]); - for(unsigned i=1;i<nga.size();++i) rtwo[i]=rtwo[0]; + if( ntarget==0 ) { + parse("RTWO",rtwo[0]); + for(unsigned i=1; i<nga.size(); ++i) rtwo[i]=rtwo[0]; } else if( ntarget!=nga.size() ) error("found wrong number of RTWO values"); double tauc=0.; @@ -153,10 +153,10 @@ pbc(true) const double ns2s = 0.000000001; const double MHz2Hz = 1000000.; - const double Kappa = 12300000000.00; // this is 1/15*S*(S+1)*gamma^2*g^2*beta^2 - // where gamma is the nuclear gyromagnetic ratio, - // g is the electronic g factor, and beta is the Bohr magneton - // in nm^6/s^2 + const double Kappa = 12300000000.00; // this is 1/15*S*(S+1)*gamma^2*g^2*beta^2 + // where gamma is the nuclear gyromagnetic ratio, + // g is the electronic g factor, and beta is the Bohr magneton + // in nm^6/s^2 constant = (4.*tauc*ns2s+(3.*tauc*ns2s)/(1+omega*omega*MHz2Hz*MHz2Hz*tauc*tauc*ns2s*ns2s))*Kappa; bool addexp=false; @@ -164,12 +164,12 @@ pbc(true) vector<double> exppre; if(addexp) { - exppre.resize( nga.size() ); + exppre.resize( nga.size() ); unsigned ntarget=0; - for(unsigned i=0;i<nga.size();++i){ - if( !parseNumbered( "PREINT", i+1, exppre[i] ) ) break; - ntarget++; + for(unsigned i=0; i<nga.size(); ++i) { + if( !parseNumbered( "PREINT", i+1, exppre[i] ) ) break; + ntarget++; } if( ntarget!=nga.size() ) error("found wrong number of PREINT values"); } @@ -178,12 +178,12 @@ pbc(true) nl= new NeighborList(gb_lista,ga_lista,true,pbc,getPbc()); // Ouput details of all contacts - unsigned index=0; - for(unsigned i=0;i<nga.size();++i){ + unsigned index=0; + for(unsigned i=0; i<nga.size(); ++i) { log.printf(" The %uth PRE is calculated using %u equivalent atoms:\n", i, nga[i]); log.printf(" %d", ga_lista[index].serial()); index++; - for(unsigned j=1;j<nga[i];j++) { + for(unsigned j=1; j<nga[i]; j++) { log.printf(" %d", ga_lista[index].serial()); index++; } @@ -193,18 +193,18 @@ pbc(true) if(pbc) log.printf(" using periodic boundary conditions\n"); else log.printf(" without periodic boundary conditions\n"); - for(unsigned i=0;i<nga.size();i++) { + for(unsigned i=0; i<nga.size(); i++) { string num; Tools::convert(i,num); addComponentWithDerivatives("pre_"+num); componentIsNotPeriodic("pre_"+num); } if(addexp) { - for(unsigned i=0;i<nga.size();i++) { + for(unsigned i=0; i<nga.size(); i++) { string num; Tools::convert(i,num); addComponent("exp_"+num); componentIsNotPeriodic("exp_"+num); - Value* comp=getPntrToComponent("exp_"+num); + Value* comp=getPntrToComponent("exp_"+num); comp->set(exppre[i]); } } @@ -213,22 +213,22 @@ pbc(true) checkRead(); } -PRE::~PRE(){ +PRE::~PRE() { delete nl; -} +} void PRE::calculate() { // cycle over the number of PRE -#pragma omp parallel for num_threads(OpenMP::getNumThreads()) - for(unsigned i=0;i<nga.size();i++) { - vector<Vector> deriv; + #pragma omp parallel for num_threads(OpenMP::getNumThreads()) + for(unsigned i=0; i<nga.size(); i++) { + vector<Vector> deriv; Tensor dervir; double pre=0; unsigned index=0; - for(unsigned k=0; k<i; k++) index+=nga[k]; - // cycle over equivalent atoms - for(unsigned j=0;j<nga[i];j++) { + for(unsigned k=0; k<i; k++) index+=nga[k]; + // cycle over equivalent atoms + for(unsigned j=0; j<nga[i]; j++) { const double c_aver=constant/((double)nga[i]); // the first atom is always the same (the paramagnetic group) const unsigned i0=nl->getClosePair(index+j).first; @@ -257,7 +257,7 @@ void PRE::calculate() val->set(ratio); setBoxDerivatives(val, fact*dervir); - for(unsigned j=0;j<nga[i];j++) { + for(unsigned j=0; j<nga[i]; j++) { const unsigned i0=nl->getClosePair(index+j).first; const unsigned i1=nl->getClosePair(index+j).second; setAtomsDerivatives(val, i0, fact*deriv[j]); diff --git a/src/colvar/PathMSD.cpp b/src/colvar/PathMSD.cpp index 7d1cca091..cdfd96ee1 100644 --- a/src/colvar/PathMSD.cpp +++ b/src/colvar/PathMSD.cpp @@ -24,26 +24,26 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { //+PLUMEDOC COLVAR PATHMSD /* -This Colvar calculates path collective variables. +This Colvar calculates path collective variables. -This is the Path Collective Variables implementation +This is the Path Collective Variables implementation ( see \cite brand07 ). -This variable computes the progress along a given set of frames that is provided -in input ("sss" component) and the distance from them ("zzz" component). +This variable computes the progress along a given set of frames that is provided +in input ("sss" component) and the distance from them ("zzz" component). (see below). \par Examples -Here below is a case where you have defined three frames and you want to +Here below is a case where you have defined three frames and you want to calculate the progress along the path and the distance from it in p1 \verbatim -p1: PATHMSD REFERENCE=file.pdb LAMBDA=500.0 NEIGH_STRIDE=4 NEIGH_SIZE=8 +p1: PATHMSD REFERENCE=file.pdb LAMBDA=500.0 NEIGH_STRIDE=4 NEIGH_SIZE=8 PRINT ARG=p1.sss,p1.zzz STRIDE=1 FILE=colvar FMT=%8.4f \endverbatim @@ -60,7 +60,7 @@ is shared, as well as most input options. */ //+ENDPLUMEDOC - + class PathMSD : public PathMSDBase { public: explicit PathMSD(const ActionOptions&); @@ -69,7 +69,7 @@ public: PLUMED_REGISTER_ACTION(PathMSD,"PATHMSD") -void PathMSD::registerKeywords(Keywords& keys){ +void PathMSD::registerKeywords(Keywords& keys) { PathMSDBase::registerKeywords(keys); componentsAreNotOptional(keys); keys.addOutputComponent("sss","default","the position on the path"); @@ -77,7 +77,7 @@ void PathMSD::registerKeywords(Keywords& keys){ } PathMSD::PathMSD(const ActionOptions&ao): -Action(ao),PathMSDBase(ao) + Action(ao),PathMSDBase(ao) { checkRead(); @@ -87,12 +87,12 @@ Action(ao),PathMSDBase(ao) // no need to read anything addComponentWithDerivatives("sss"); componentIsNotPeriodic("sss"); addComponentWithDerivatives("zzz"); componentIsNotPeriodic("zzz"); - requestAtoms(pdbv[0].getAtomNumbers()); + requestAtoms(pdbv[0].getAtomNumbers()); double i=1.; - for(unsigned it=0 ;it<nframes ;++it){ - vector<double> v; v.push_back(i); - indexvec.push_back(v);i+=1.; + for(unsigned it=0 ; it<nframes ; ++it) { + vector<double> v; v.push_back(i); + indexvec.push_back(v); i+=1.; } } diff --git a/src/colvar/PathMSDBase.cpp b/src/colvar/PathMSDBase.cpp index 6e283b27b..cda02bdb9 100644 --- a/src/colvar/PathMSDBase.cpp +++ b/src/colvar/PathMSDBase.cpp @@ -31,10 +31,10 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { -void PathMSDBase::registerKeywords(Keywords& keys){ +void PathMSDBase::registerKeywords(Keywords& keys) { Colvar::registerKeywords(keys); keys.remove("NOPBC"); keys.add("compulsory","LAMBDA","the lambda parameter is needed for smoothing, is in the units of plumed"); @@ -44,10 +44,10 @@ void PathMSDBase::registerKeywords(Keywords& keys){ } PathMSDBase::PathMSDBase(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao), -neigh_size(-1), -neigh_stride(-1), -nframes(0) + PLUMED_COLVAR_INIT(ao), + neigh_size(-1), + neigh_stride(-1), + nframes(0) { parse("LAMBDA",lambda); parse("NEIGH_SIZE",neigh_size); @@ -61,46 +61,46 @@ nframes(0) { log<<"Opening reference file "<<reference.c_str()<<"\n"; bool do_read=true; - while (do_read){ - PDB mypdb; - RMSD mymsd; - do_read=mypdb.readFromFilepointer(fp,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength()); - if(do_read){ - nframes++; - if(mypdb.getAtomNumbers().size()==0) error("number of atoms in a frame should be more than zero"); - unsigned nat=mypdb.getAtomNumbers().size(); - if(nat!=mypdb.getAtomNumbers().size()) error("frames should have the same number of atoms"); - if(aaa.empty()) aaa=mypdb.getAtomNumbers(); - if(aaa!=mypdb.getAtomNumbers()) error("frames should contain same atoms in same order"); - log<<"Found PDB: "<<nframes<<" containing "<<mypdb.getAtomNumbers().size()<<" atoms\n"; - pdbv.push_back(mypdb); -// requestAtoms(mypdb.getAtomNumbers()); // is done in non base classes - derivs_s.resize(mypdb.getAtomNumbers().size()); - derivs_z.resize(mypdb.getAtomNumbers().size()); - mymsd.set(mypdb,"OPTIMAL"); - msdv.push_back(mymsd); // the vector that stores the frames - //log<<mypdb; - }else{break ;} + while (do_read) { + PDB mypdb; + RMSD mymsd; + do_read=mypdb.readFromFilepointer(fp,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength()); + if(do_read) { + nframes++; + if(mypdb.getAtomNumbers().size()==0) error("number of atoms in a frame should be more than zero"); + unsigned nat=mypdb.getAtomNumbers().size(); + if(nat!=mypdb.getAtomNumbers().size()) error("frames should have the same number of atoms"); + if(aaa.empty()) aaa=mypdb.getAtomNumbers(); + if(aaa!=mypdb.getAtomNumbers()) error("frames should contain same atoms in same order"); + log<<"Found PDB: "<<nframes<<" containing "<<mypdb.getAtomNumbers().size()<<" atoms\n"; + pdbv.push_back(mypdb); +// requestAtoms(mypdb.getAtomNumbers()); // is done in non base classes + derivs_s.resize(mypdb.getAtomNumbers().size()); + derivs_z.resize(mypdb.getAtomNumbers().size()); + mymsd.set(mypdb,"OPTIMAL"); + msdv.push_back(mymsd); // the vector that stores the frames + //log<<mypdb; + } else {break ;} } fclose (fp); - log<<"Found TOTAL "<<nframes<< " PDB in the file "<<reference.c_str()<<" \n"; + log<<"Found TOTAL "<<nframes<< " PDB in the file "<<reference.c_str()<<" \n"; if(nframes==0) error("at least one frame expected"); - } - if(neigh_stride>0 || neigh_size>0){ - if(neigh_size>int(nframes)){ - log.printf(" List size required ( %d ) is too large: resizing to the maximum number of frames required: %u \n",neigh_size,nframes); - neigh_size=nframes; - } - log.printf(" Neighbor list enabled: \n"); - log.printf(" size : %d elements\n",neigh_size); - log.printf(" stride : %d timesteps \n",neigh_stride); - }else{ - log.printf(" Neighbor list NOT enabled \n"); + } + if(neigh_stride>0 || neigh_size>0) { + if(neigh_size>int(nframes)) { + log.printf(" List size required ( %d ) is too large: resizing to the maximum number of frames required: %u \n",neigh_size,nframes); + neigh_size=nframes; + } + log.printf(" Neighbor list enabled: \n"); + log.printf(" size : %d elements\n",neigh_size); + log.printf(" stride : %d timesteps \n",neigh_stride); + } else { + log.printf(" Neighbor list NOT enabled \n"); } } -void PathMSDBase::calculate(){ +void PathMSDBase::calculate() { if(neigh_size>0 && getExchangeStep()) error("Neighbor lists for this collective variable are not compatible with replica exchange, sorry for that!"); @@ -108,12 +108,12 @@ void PathMSDBase::calculate(){ // resize the list to full - if(imgVec.empty()){ // this is the signal that means: recalculate all - imgVec.resize(nframes); - for(unsigned i=0;i<nframes;i++){ - imgVec[i].property=indexvec[i]; - imgVec[i].index=i; - } + if(imgVec.empty()) { // this is the signal that means: recalculate all + imgVec.resize(nframes); + for(unsigned i=0; i<nframes; i++) { + imgVec[i].property=indexvec[i]; + imgVec[i].index=i; + } } // THIS IS THE HEAVY PART (RMSD STUFF) @@ -130,17 +130,17 @@ void PathMSDBase::calculate(){ std::vector<Vector> tmp_derivs2(imgVec.size()*nat); // if imgVec.size() is less than nframes, it means that only some msd will be calculated - for(unsigned i=rank;i<imgVec.size();i+=stride){ + for(unsigned i=rank; i<imgVec.size(); i+=stride) { // store temporary local results tmp_distances[i]=msdv[imgVec[i].index].calculate(getPositions(),tmp_derivs,true); plumed_assert(tmp_derivs.size()==nat); - for(unsigned j=0;j<nat;j++) tmp_derivs2[i*nat+j]=tmp_derivs[j]; + for(unsigned j=0; j<nat; j++) tmp_derivs2[i*nat+j]=tmp_derivs[j]; } // reduce over all processors comm.Sum(tmp_distances); comm.Sum(tmp_derivs2); // assign imgVec[i].distance and imgVec[i].distder - for(unsigned i=0;i<imgVec.size();i++){ + for(unsigned i=0; i<imgVec.size(); i++) { imgVec[i].distance=tmp_distances[i]; imgVec[i].distder.assign(&tmp_derivs2[i*nat],nat+&tmp_derivs2[i*nat]); } @@ -148,65 +148,65 @@ void PathMSDBase::calculate(){ // END OF THE HEAVY PART vector<Value*> val_s_path; - if(labels.size()>0){ - for(unsigned i=0;i<labels.size();i++){ val_s_path.push_back(getPntrToComponent(labels[i].c_str()));} - }else{ - val_s_path.push_back(getPntrToComponent("sss")); - } + if(labels.size()>0) { + for(unsigned i=0; i<labels.size(); i++) { val_s_path.push_back(getPntrToComponent(labels[i].c_str()));} + } else { + val_s_path.push_back(getPntrToComponent("sss")); + } Value* val_z_path=getPntrToComponent("zzz"); - vector<double> s_path(val_s_path.size());for(unsigned i=0;i<s_path.size();i++)s_path[i]=0.; + vector<double> s_path(val_s_path.size()); for(unsigned i=0; i<s_path.size(); i++)s_path[i]=0.; double partition=0.; double tmp; // clean vector - for(unsigned i=0;i< derivs_z.size();i++){derivs_z[i].zero();} + for(unsigned i=0; i< derivs_z.size(); i++) {derivs_z[i].zero();} - for(auto & it : imgVec){ + for(auto & it : imgVec) { it.similarity=exp(-lambda*(it.distance)); //log<<"DISTANCE "<<(*it).distance<<"\n"; - for(unsigned i=0;i<s_path.size();i++){ - s_path[i]+=(it.property[i])*it.similarity; + for(unsigned i=0; i<s_path.size(); i++) { + s_path[i]+=(it.property[i])*it.similarity; } partition+=it.similarity; } - for(unsigned i=0;i<s_path.size();i++){ s_path[i]/=partition; val_s_path[i]->set(s_path[i]) ;} + for(unsigned i=0; i<s_path.size(); i++) { s_path[i]/=partition; val_s_path[i]->set(s_path[i]) ;} val_z_path->set(-(1./lambda)*std::log(partition)); - for(unsigned j=0;j<s_path.size();j++){ + for(unsigned j=0; j<s_path.size(); j++) { // clean up - for(unsigned i=0;i< derivs_s.size();i++){derivs_s[i].zero();} - // do the derivative - for(const auto & it : imgVec){ - double expval=it.similarity; - tmp=lambda*expval*(s_path[j]-it.property[j])/partition; - for(unsigned i=0;i< derivs_s.size();i++){ derivs_s[i]+=tmp*it.distder[i] ;} - if(j==0){for(unsigned i=0;i< derivs_z.size();i++){ derivs_z[i]+=it.distder[i]*expval/partition;}} + for(unsigned i=0; i< derivs_s.size(); i++) {derivs_s[i].zero();} + // do the derivative + for(const auto & it : imgVec) { + double expval=it.similarity; + tmp=lambda*expval*(s_path[j]-it.property[j])/partition; + for(unsigned i=0; i< derivs_s.size(); i++) { derivs_s[i]+=tmp*it.distder[i] ;} + if(j==0) {for(unsigned i=0; i< derivs_z.size(); i++) { derivs_z[i]+=it.distder[i]*expval/partition;}} } - for(unsigned i=0;i< derivs_s.size();i++){ - setAtomsDerivatives (val_s_path[j],i,derivs_s[i]); - if(j==0){setAtomsDerivatives (val_z_path,i,derivs_z[i]);} + for(unsigned i=0; i< derivs_s.size(); i++) { + setAtomsDerivatives (val_s_path[j],i,derivs_s[i]); + if(j==0) {setAtomsDerivatives (val_z_path,i,derivs_z[i]);} } } - for(unsigned i=0;i<val_s_path.size();++i) setBoxDerivativesNoPbc(val_s_path[i]); + for(unsigned i=0; i<val_s_path.size(); ++i) setBoxDerivativesNoPbc(val_s_path[i]); setBoxDerivativesNoPbc(val_z_path); // // here set next round neighbors // - if (neigh_size>0){ - //if( int(getStep())%int(neigh_stride/getTimeStep())==0 ){ - // enforce consistency: the stride is in time steps - if( int(getStep())%int(neigh_stride)==0 ){ - - // next round do it all:empty the vector - imgVec.clear(); - } - // time to analyze the results: - if(imgVec.size()==nframes){ - //sort by msd - sort(imgVec.begin(), imgVec.end(), imgOrderByDist()); - //resize - imgVec.resize(neigh_size); - } + if (neigh_size>0) { + //if( int(getStep())%int(neigh_stride/getTimeStep())==0 ){ + // enforce consistency: the stride is in time steps + if( int(getStep())%int(neigh_stride)==0 ) { + + // next round do it all:empty the vector + imgVec.clear(); + } + // time to analyze the results: + if(imgVec.size()==nframes) { + //sort by msd + sort(imgVec.begin(), imgVec.end(), imgOrderByDist()); + //resize + imgVec.resize(neigh_size); + } } //log.printf("CALCULATION DONE! \n"); } diff --git a/src/colvar/PathMSDBase.h b/src/colvar/PathMSDBase.h index 4451bffc7..dae1603cb 100644 --- a/src/colvar/PathMSDBase.h +++ b/src/colvar/PathMSDBase.h @@ -29,34 +29,34 @@ #include "tools/RMSD.h" #include "tools/Tools.h" -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { class PathMSDBase : public Colvar { -/// this class is a general container for path stuff +/// this class is a general container for path stuff class ImagePath { - public: - // cardinal indexing: needed to map over msd - unsigned index; - // spiwok indexing - std::vector<double> property; - // distance - double distance; - // similarity (exp - lambda distance) or other - double similarity; - // derivatives of the distance - std::vector<Vector> distder; - // here one can add a pointer to a value (hypothetically providing a distance from a point) + public: + // cardinal indexing: needed to map over msd + unsigned index; + // spiwok indexing + std::vector<double> property; + // distance + double distance; + // similarity (exp - lambda distance) or other + double similarity; + // derivatives of the distance + std::vector<Vector> distder; + // here one can add a pointer to a value (hypothetically providing a distance from a point) }; struct imgOrderByDist { - bool operator ()(ImagePath const& a, ImagePath const& b) { - return (a).distance < (b).distance; - } + bool operator ()(ImagePath const& a, ImagePath const& b) { + return (a).distance < (b).distance; + } }; struct imgOrderBySimilarity { - bool operator ()(ImagePath const& a, ImagePath const& b) { - return (a).similarity > (b).similarity; - } + bool operator ()(ImagePath const& a, ImagePath const& b) { + return (a).similarity > (b).similarity; + } }; double lambda; @@ -66,7 +66,7 @@ class PathMSDBase : public Colvar { std::string reference; std::vector<Vector> derivs_s; std::vector<Vector> derivs_z; - std::vector <ImagePath> imgVec; // this can be used for doing neighlist + std::vector <ImagePath> imgVec; // this can be used for doing neighlist protected: std::vector<PDB> pdbv; std::vector<std::string> labels; diff --git a/src/colvar/Position.cpp b/src/colvar/Position.cpp index ab34c3ae1..a381e039e 100644 --- a/src/colvar/Position.cpp +++ b/src/colvar/Position.cpp @@ -28,8 +28,8 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { //+PLUMEDOC COLVAR POSITION /* @@ -37,7 +37,7 @@ Calculate the components of the position of an atom. Notice that single components will not have the proper periodicity! If you need the values to be consistent through PBC you should use SCALED_COMPONENTS, -which defines values that by construction are in the -0.5,0.5 domain. This is +which defines values that by construction are in the -0.5,0.5 domain. This is similar to the equivalent flag for \ref DISTANCE. Also notice that by default the minimal image distance from the origin is considered (can be changed with NOPBC). @@ -45,7 +45,7 @@ origin is considered (can be changed with NOPBC). \attention This variable should be used with extreme care since it allows to easily go into troubles. See comments below. -This variable can be safely used only if +This variable can be safely used only if Hamiltonian is not invariant for translation (i.e. there are other absolute positions which are biased, e.g. by position restraints) and cell size and shapes are fixed through the simulation. @@ -65,7 +65,7 @@ PRINT ARG=p.x,p.y,p.z */ //+ENDPLUMEDOC - + class Position : public Colvar { bool scaled_components; bool pbc; @@ -79,7 +79,7 @@ public: PLUMED_REGISTER_ACTION(Position,"POSITION") -void Position::registerKeywords( Keywords& keys ){ +void Position::registerKeywords( Keywords& keys ) { Colvar::registerKeywords( keys ); componentsAreNotOptional(keys); keys.add("atoms","ATOM","the atom number"); @@ -93,9 +93,9 @@ void Position::registerKeywords( Keywords& keys ){ } Position::Position(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao), -scaled_components(false), -pbc(true) + PLUMED_COLVAR_INIT(ao), + scaled_components(false), + pbc(true) { vector<AtomNumber> atoms; parseAtomList("ATOM",atoms); @@ -111,7 +111,7 @@ pbc(true) if(pbc) log.printf(" using periodic boundary conditions\n"); else log.printf(" without periodic boundary conditions\n"); - if(scaled_components){ + if(scaled_components) { addComponentWithDerivatives("a"); componentIsPeriodic("a","-0.5","+0.5"); addComponentWithDerivatives("b"); componentIsPeriodic("b","-0.5","+0.5"); addComponentWithDerivatives("c"); componentIsPeriodic("c","-0.5","+0.5"); @@ -127,16 +127,16 @@ pbc(true) // calculator -void Position::calculate(){ +void Position::calculate() { Vector distance; - if(pbc){ + if(pbc) { distance=pbcDistance(Vector(0.0,0.0,0.0),getPosition(0)); } else { distance=delta(Vector(0.0,0.0,0.0),getPosition(0)); } - if(scaled_components){ + if(scaled_components) { Value* valuea=getPntrToComponent("a"); Value* valueb=getPntrToComponent("b"); Value* valuec=getPntrToComponent("c"); diff --git a/src/colvar/PropertyMap.cpp b/src/colvar/PropertyMap.cpp index 89658cfad..a8a21fef2 100644 --- a/src/colvar/PropertyMap.cpp +++ b/src/colvar/PropertyMap.cpp @@ -24,10 +24,10 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { -//+PLUMEDOC COLVAR PROPERTYMAP +//+PLUMEDOC COLVAR PROPERTYMAP /* Calculate generic property maps. @@ -42,7 +42,7 @@ Y=\frac{\sum_i Y_i*\exp(-\lambda D_i(x))}{\sum_i \exp(-\lambda D_i(x))} \\ zzz=-\frac{1}{\lambda}\log(\sum_i \exp(-\lambda D_i(x))) \f} -where the parameters \f$X_i\f$ and \f$Y_i\f$ are provided in the input pdb (allv.pdb in this case) and +where the parameters \f$X_i\f$ and \f$Y_i\f$ are provided in the input pdb (allv.pdb in this case) and \f$D_i(x)\f$ is the MSD after optimal alignment calculated on the pdb frames you input (see Kearsley). \par Examples @@ -55,17 +55,17 @@ note that NEIGH_STRIDE=4 NEIGH_SIZE=8 control the neighborlist parameter (option recommended for performance) and states that the neighbor list will be calculated every 4 timesteps and consider only the closest 8 member to the actual md snapshots. -In this case the input line instructs plumed to look for two properties X and Y with attached values in the REMARK +In this case the input line instructs plumed to look for two properties X and Y with attached values in the REMARK line of the reference pdb (Note: No spaces from X and = and 1 !!!!). e.g. \verbatim -REMARK X=1 Y=2 +REMARK X=1 Y=2 ATOM 1 CL ALA 1 -3.171 0.295 2.045 1.00 1.00 ATOM 5 CLP ALA 1 -1.819 -0.143 1.679 1.00 1.00 ....... END -REMARK X=2 Y=3 +REMARK X=2 Y=3 ATOM 1 CL ALA 1 -3.175 0.365 2.024 1.00 1.00 ATOM 5 CLP ALA 1 -1.814 -0.106 1.685 1.00 1.00 .... @@ -78,7 +78,7 @@ is shared, as well as most input options. */ //+ENDPLUMEDOC - + class PropertyMap : public PathMSDBase { public: explicit PropertyMap(const ActionOptions&); @@ -87,7 +87,7 @@ public: PLUMED_REGISTER_ACTION(PropertyMap,"PROPERTYMAP") -void PropertyMap::registerKeywords(Keywords& keys){ +void PropertyMap::registerKeywords(Keywords& keys) { PathMSDBase::registerKeywords(keys); keys.add("compulsory","PROPERTY","the property to be used in the indexing: this goes in the REMARK field of the reference"); ActionWithValue::useCustomisableComponents(keys); @@ -95,45 +95,45 @@ void PropertyMap::registerKeywords(Keywords& keys){ } PropertyMap::PropertyMap(const ActionOptions&ao): -Action(ao), -PathMSDBase(ao) + Action(ao), + PathMSDBase(ao) { - // this is the only additional keyword needed + // this is the only additional keyword needed parseVector("PROPERTY",labels); checkRead(); log<<" Bibliography " - <<plumed.cite("Spiwok V, Kralova B J. Chem. Phys. 135, 224504 (2011)") - <<"\n"; - if(labels.size()==0){ - char buf[500]; - sprintf(buf,"Need to specify PROPERTY with this action\n"); - plumed_merror(buf); - }else{ - for(unsigned i=0;i<labels.size();i++){ - log<<" found custom propety to be found in the REMARK line: "<<labels[i].c_str()<<"\n"; - addComponentWithDerivatives(labels[i]); componentIsNotPeriodic(labels[i]); - } - // add distance anyhow - addComponentWithDerivatives("zzz"); componentIsNotPeriodic("zzz"); - //reparse the REMARK field and pick the index - for(unsigned i=0;i<pdbv.size();i++){ - vector<std::string> myv(pdbv[i].getRemark()); - // now look for X=1.34555 Y=5.6677 - vector<double> labelvals; - for(unsigned j=0;j<labels.size();j++){ - double val; - if(Tools::parse(myv,labels[j],val)){labelvals.push_back(val);} - else{ - char buf[500]; - sprintf(buf,"PROPERTY LABEL \" %s \" NOT FOUND IN REMARK FOR FRAME %u \n",labels[j].c_str(),i); - plumed_merror(buf); - }; - } - indexvec.push_back(labelvals); + <<plumed.cite("Spiwok V, Kralova B J. Chem. Phys. 135, 224504 (2011)") + <<"\n"; + if(labels.size()==0) { + char buf[500]; + sprintf(buf,"Need to specify PROPERTY with this action\n"); + plumed_merror(buf); + } else { + for(unsigned i=0; i<labels.size(); i++) { + log<<" found custom propety to be found in the REMARK line: "<<labels[i].c_str()<<"\n"; + addComponentWithDerivatives(labels[i]); componentIsNotPeriodic(labels[i]); + } + // add distance anyhow + addComponentWithDerivatives("zzz"); componentIsNotPeriodic("zzz"); + //reparse the REMARK field and pick the index + for(unsigned i=0; i<pdbv.size(); i++) { + vector<std::string> myv(pdbv[i].getRemark()); + // now look for X=1.34555 Y=5.6677 + vector<double> labelvals; + for(unsigned j=0; j<labels.size(); j++) { + double val; + if(Tools::parse(myv,labels[j],val)) {labelvals.push_back(val);} + else { + char buf[500]; + sprintf(buf,"PROPERTY LABEL \" %s \" NOT FOUND IN REMARK FOR FRAME %u \n",labels[j].c_str(),i); + plumed_merror(buf); + }; } + indexvec.push_back(labelvals); + } } - requestAtoms(pdbv[0].getAtomNumbers()); - + requestAtoms(pdbv[0].getAtomNumbers()); + } } diff --git a/src/colvar/Puckering.cpp b/src/colvar/Puckering.cpp index dc19b35e1..b90bdfbc4 100644 --- a/src/colvar/Puckering.cpp +++ b/src/colvar/Puckering.cpp @@ -30,14 +30,14 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { //+PLUMEDOC COLVAR PUCKERING /* Calculate sugar pseudorotation coordinates. - This command can be used to calculate ring's pseudorotations in sugars (puckers). It works for both + This command can be used to calculate ring's pseudorotations in sugars (puckers). It works for both 5-membered and 6-membered rings. Notice that there are two different implementations depending if one passes 5 or 6 atoms in the ATOMS keyword. @@ -49,16 +49,16 @@ namespace colvar{ The five atoms should be provided as C4',O4',C1',C2',C3'. Notice that this is the same order that can be obtained using the \ref MOLINFO syntax (see example below). - For 6-membered rings the implementation is the general Cremer-Pople one \cite cremer1975general + For 6-membered rings the implementation is the general Cremer-Pople one \cite cremer1975general as also discussed in \cite biarnes2007conformational . This implementation provides both a triplet with Cartesian components (qx, qy, and qz) and a triplet of polar components (amplitude, phi, and theta). Applications of this particular implentation are to be published (paper in preparation). - + Components of this action are: - + \par Examples - + This input tells plumed to print the puckering phase angle of the 3rd nucleotide of a RNA molecule on file COLVAR. \verbatim MOLINFO STRUCTURE=rna.pdb MOLTYPE=rna @@ -68,7 +68,7 @@ namespace colvar{ */ //+ENDPLUMEDOC - + class Puckering : public Colvar { public: @@ -81,42 +81,42 @@ public: PLUMED_REGISTER_ACTION(Puckering,"PUCKERING") -void Puckering::registerKeywords(Keywords& keys){ - Colvar::registerKeywords( keys ); - keys.remove("NOPBC"); - keys.add("atoms","ATOMS","the five or six atoms of the sugar ring in the proper order"); - keys.addOutputComponent("phs","default","Pseudorotation phase (5 membered rings)"); - keys.addOutputComponent("amp","default","Pseudorotation amplitude (5 membered rings)"); - keys.addOutputComponent("Zx","default","Pseudorotation x cartesian component (5 membered rings)"); - keys.addOutputComponent("Zy","default","Pseudorotation y cartesian component (5 membered rings)"); - keys.addOutputComponent("phi","default","Pseudorotation phase (6 membered rings)"); - keys.addOutputComponent("theta","default","Theta angle (6 membered rings)"); - keys.addOutputComponent("amplitude","default","Pseudorotation amplitude (6 membered rings)"); - keys.addOutputComponent("qx","default","Cartesian component x (6 membered rings)"); - keys.addOutputComponent("qy","default","Cartesian component y (6 membered rings)"); - keys.addOutputComponent("qz","default","Cartesian component z (6 membered rings)"); +void Puckering::registerKeywords(Keywords& keys) { + Colvar::registerKeywords( keys ); + keys.remove("NOPBC"); + keys.add("atoms","ATOMS","the five or six atoms of the sugar ring in the proper order"); + keys.addOutputComponent("phs","default","Pseudorotation phase (5 membered rings)"); + keys.addOutputComponent("amp","default","Pseudorotation amplitude (5 membered rings)"); + keys.addOutputComponent("Zx","default","Pseudorotation x cartesian component (5 membered rings)"); + keys.addOutputComponent("Zy","default","Pseudorotation y cartesian component (5 membered rings)"); + keys.addOutputComponent("phi","default","Pseudorotation phase (6 membered rings)"); + keys.addOutputComponent("theta","default","Theta angle (6 membered rings)"); + keys.addOutputComponent("amplitude","default","Pseudorotation amplitude (6 membered rings)"); + keys.addOutputComponent("qx","default","Cartesian component x (6 membered rings)"); + keys.addOutputComponent("qy","default","Cartesian component y (6 membered rings)"); + keys.addOutputComponent("qz","default","Cartesian component z (6 membered rings)"); } Puckering::Puckering(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao) + PLUMED_COLVAR_INIT(ao) { vector<AtomNumber> atoms; parseAtomList("ATOMS",atoms); if(atoms.size()!=5 && atoms.size()!=6) error("only for 5 or 6-membered rings"); checkRead(); - - if(atoms.size()==5){ + + if(atoms.size()==5) { log.printf(" between atoms %d %d %d %d %d\n",atoms[0].serial(),atoms[1].serial(),atoms[2].serial(),atoms[3].serial(),atoms[4].serial()); - } else if(atoms.size()==6){ + } else if(atoms.size()==6) { log.printf(" between atoms %d %d %d %d %d %d\n",atoms[0].serial(),atoms[1].serial(),atoms[2].serial(),atoms[3].serial(),atoms[4].serial(),atoms[5].serial()); } else error("ATOMS should specify 5 atoms"); - - if(atoms.size()==5){ + + if(atoms.size()==5) { addComponentWithDerivatives("phs"); componentIsPeriodic("phs","-pi","pi"); addComponentWithDerivatives("amp"); componentIsNotPeriodic("amp"); addComponentWithDerivatives("Zx"); componentIsNotPeriodic("Zx"); addComponentWithDerivatives("Zy"); componentIsNotPeriodic("Zy"); - } else if(atoms.size()==6){ + } else if(atoms.size()==6) { addComponentWithDerivatives("qx"); componentIsNotPeriodic("qx"); addComponentWithDerivatives("qy"); componentIsNotPeriodic("qy"); addComponentWithDerivatives("qz"); componentIsNotPeriodic("qz"); @@ -134,27 +134,27 @@ PLUMED_COLVAR_INIT(ao) } // calculator -void Puckering::calculate(){ +void Puckering::calculate() { makeWhole(); if(getNumberOfAtoms()==5) calculate5m(); else calculate6m(); } -void Puckering::calculate5m(){ +void Puckering::calculate5m() { Vector d0,d1,d2,d3,d4,d5; - + d0=delta(getPosition(2),getPosition(1)); d1=delta(getPosition(3),getPosition(2)); d2=delta(getPosition(4),getPosition(3)); d3=delta(getPosition(4),getPosition(3)); d4=delta(getPosition(0),getPosition(4)); d5=delta(getPosition(1),getPosition(0)); - + Vector dd0,dd1,dd2,dd3,dd4,dd5; - + PLMD::Torsion t; - + double v1=t.compute(d0,d1,d2,dd0,dd1,dd2); double v3=t.compute(d3,d4,d5,dd3,dd4,dd5); @@ -162,31 +162,31 @@ void Puckering::calculate5m(){ double Zy=(v1-v3)/(2.0*sin(4.0*pi/5.0)); double phase=atan2(Zy,Zx); double amplitude=sqrt(Zx*Zx+Zy*Zy); - + Vector dZx_dR[5]; Vector dZy_dR[5]; - + dZx_dR[0]=(dd5-dd4); dZx_dR[1]=(dd0-dd5); dZx_dR[2]=(dd1-dd0); dZx_dR[3]=(dd2+dd3-dd1); dZx_dR[4]=(dd4-dd3-dd2); - + dZy_dR[0]=(dd4-dd5); dZy_dR[1]=(dd0+dd5); dZy_dR[2]=(dd1-dd0); dZy_dR[3]=(dd2-dd3-dd1); dZy_dR[4]=(dd3-dd4-dd2); - - for(unsigned j=0;j<5;j++) dZx_dR[j]*=(1.0/(2.0*cos(4.0*pi/5.0))); - for(unsigned j=0;j<5;j++) dZy_dR[j]*=(1.0/(2.0*sin(4.0*pi/5.0))); - + + for(unsigned j=0; j<5; j++) dZx_dR[j]*=(1.0/(2.0*cos(4.0*pi/5.0))); + for(unsigned j=0; j<5; j++) dZy_dR[j]*=(1.0/(2.0*sin(4.0*pi/5.0))); + Vector dphase_dR[5]; - for(unsigned j=0;j<5;j++) dphase_dR[j]=(1.0/(Zx*Zx+Zy*Zy))*(-Zy*dZx_dR[j] + Zx*dZy_dR[j]); - + for(unsigned j=0; j<5; j++) dphase_dR[j]=(1.0/(Zx*Zx+Zy*Zy))*(-Zy*dZx_dR[j] + Zx*dZy_dR[j]); + Vector damplitude_dR[5]; - for(unsigned j=0;j<5;j++) damplitude_dR[j]=(1.0/amplitude)*(Zx*dZx_dR[j] + Zy*dZy_dR[j]); - + for(unsigned j=0; j<5; j++) damplitude_dR[j]=(1.0/amplitude)*(Zx*dZx_dR[j] + Zy*dZy_dR[j]); + Value* vzx=getPntrToComponent("Zx"); vzx->set(Zx); setAtomsDerivatives (vzx,0, dZx_dR[0]); @@ -195,7 +195,7 @@ void Puckering::calculate5m(){ setAtomsDerivatives (vzx,3, dZx_dR[3]); setAtomsDerivatives (vzx,4, dZx_dR[4]); setBoxDerivativesNoPbc(vzx); - + Value* vzy=getPntrToComponent("Zy"); vzy->set(Zy); setAtomsDerivatives (vzy,0, dZy_dR[0]); @@ -214,7 +214,7 @@ void Puckering::calculate5m(){ setAtomsDerivatives (vph,3, dphase_dR[3]); setAtomsDerivatives (vph,4, dphase_dR[4]); setBoxDerivativesNoPbc(vph); - + Value* vam=getPntrToComponent("amp"); vam->set(amplitude); setAtomsDerivatives (vam,0, damplitude_dR[0]); @@ -224,22 +224,22 @@ void Puckering::calculate5m(){ setAtomsDerivatives (vam,4, damplitude_dR[4]); setBoxDerivativesNoPbc(vam); - + } -void Puckering::calculate6m(){ +void Puckering::calculate6m() { vector<Vector> r(6); - for(unsigned i=0;i<6;i++) r[i]=getPosition(i); + for(unsigned i=0; i<6; i++) r[i]=getPosition(i); vector<Vector> R(6); Vector center; - for(unsigned j=0;j<6;j++) center+=r[j]/6.0; - for(unsigned j=0;j<6;j++) R[j]=(r[j]-center); + for(unsigned j=0; j<6; j++) center+=r[j]/6.0; + for(unsigned j=0; j<6; j++) R[j]=(r[j]-center); Vector Rp,Rpp; - for(unsigned j=0;j<6;j++) Rp +=R[j]*sin(2.0/6.0*pi*j); - for(unsigned j=0;j<6;j++) Rpp+=R[j]*cos(2.0/6.0*pi*j); + for(unsigned j=0; j<6; j++) Rp +=R[j]*sin(2.0/6.0*pi*j); + for(unsigned j=0; j<6; j++) Rpp+=R[j]*cos(2.0/6.0*pi*j); Vector n=crossProduct(Rp,Rpp); Vector nhat=n/modulo(n); @@ -252,165 +252,165 @@ void Puckering::calculate6m(){ Tensor dnhat_dRpp=matmul(dnhat_dn,dn_dRpp); vector<double> z(6); - for(unsigned j=0;j<6;j++) z[j]=dotProduct(R[j],nhat); + for(unsigned j=0; j<6; j++) z[j]=dotProduct(R[j],nhat); vector<vector<Vector> > dz_dR(6); - for(unsigned j=0;j<6;j++) dz_dR[j].resize(6); + for(unsigned j=0; j<6; j++) dz_dR[j].resize(6); - for(unsigned i=0;i<6;i++) for(unsigned j=0;j<6;j++){ - if(i==j) dz_dR[i][j]+=nhat; - dz_dR[i][j]+=matmul(R[i],dnhat_dRp)*sin(2.0/6.0*pi*j); - dz_dR[i][j]+=matmul(R[i],dnhat_dRpp)*cos(2.0/6.0*pi*j); - } + for(unsigned i=0; i<6; i++) for(unsigned j=0; j<6; j++) { + if(i==j) dz_dR[i][j]+=nhat; + dz_dR[i][j]+=matmul(R[i],dnhat_dRp)*sin(2.0/6.0*pi*j); + dz_dR[i][j]+=matmul(R[i],dnhat_dRpp)*cos(2.0/6.0*pi*j); + } double B=0.0; - for(unsigned j=0;j<6;j++) B+=z[j]*cos(4.0/6.0*pi*j); + for(unsigned j=0; j<6; j++) B+=z[j]*cos(4.0/6.0*pi*j); vector<Vector> dB_dR(6); - for(unsigned i=0;i<6;i++) for(unsigned j=0;j<6;j++){ - dB_dR[i]+=dz_dR[j][i]*cos(4.0/6.0*pi*j); - } + for(unsigned i=0; i<6; i++) for(unsigned j=0; j<6; j++) { + dB_dR[i]+=dz_dR[j][i]*cos(4.0/6.0*pi*j); + } Vector Bsum; - for(unsigned j=0;j<6;j++) Bsum+=dB_dR[j]; - for(unsigned j=0;j<6;j++) dB_dR[j]-=Bsum/6.0;; + for(unsigned j=0; j<6; j++) Bsum+=dB_dR[j]; + for(unsigned j=0; j<6; j++) dB_dR[j]-=Bsum/6.0;; double A=0.0; - for(unsigned j=0;j<6;j++) A+=z[j]*sin(4.0/6.0*pi*j); + for(unsigned j=0; j<6; j++) A+=z[j]*sin(4.0/6.0*pi*j); vector<Vector> dA_dR(6); - for(unsigned i=0;i<6;i++) for(unsigned j=0;j<6;j++){ - dA_dR[i]+=dz_dR[j][i]*sin(4.0/6.0*pi*j); - } + for(unsigned i=0; i<6; i++) for(unsigned j=0; j<6; j++) { + dA_dR[i]+=dz_dR[j][i]*sin(4.0/6.0*pi*j); + } Vector Asum; - for(unsigned j=0;j<6;j++) Asum+=dA_dR[j]; - for(unsigned j=0;j<6;j++) dA_dR[j]-=Asum/6.0;; + for(unsigned j=0; j<6; j++) Asum+=dA_dR[j]; + for(unsigned j=0; j<6; j++) dA_dR[j]-=Asum/6.0;; double C=0.0; - for(unsigned j=0;j<6;j++) C+=z[j]*Tools::fastpow(-1.0,(j)); + for(unsigned j=0; j<6; j++) C+=z[j]*Tools::fastpow(-1.0,(j)); vector<Vector> dC_dR(6); - for(unsigned i=0;i<6;i++) for(unsigned j=0;j<6;j++){ - dC_dR[i]+=dz_dR[j][i]*Tools::fastpow(-1.0,(j)); - } + for(unsigned i=0; i<6; i++) for(unsigned j=0; j<6; j++) { + dC_dR[i]+=dz_dR[j][i]*Tools::fastpow(-1.0,(j)); + } Vector Csum; - for(unsigned j=0;j<6;j++) Csum+=dC_dR[j]; - for(unsigned j=0;j<6;j++) dC_dR[j]-=Csum/6.0;; + for(unsigned j=0; j<6; j++) Csum+=dC_dR[j]; + for(unsigned j=0; j<6; j++) dC_dR[j]-=Csum/6.0;; // qx - double qx = A/sqrt(3); + double qx = A/sqrt(3); // qx derivaties - vector<Vector> dqx_dR(6); - for(unsigned j=0;j<6;j++){ - dqx_dR[j]=1/sqrt(3) * dA_dR[j]; - } + vector<Vector> dqx_dR(6); + for(unsigned j=0; j<6; j++) { + dqx_dR[j]=1/sqrt(3) * dA_dR[j]; + } - Value* vqx=getPntrToComponent("qx"); - vqx->set(qx); - setAtomsDerivatives (vqx,0, dqx_dR[0] ); - setAtomsDerivatives (vqx,1, dqx_dR[1] ); - setAtomsDerivatives (vqx,2, dqx_dR[2] ); - setAtomsDerivatives (vqx,3, dqx_dR[3] ); - setAtomsDerivatives (vqx,4, dqx_dR[4] ); - setAtomsDerivatives (vqx,5, dqx_dR[5] ); - setBoxDerivativesNoPbc(vqx); + Value* vqx=getPntrToComponent("qx"); + vqx->set(qx); + setAtomsDerivatives (vqx,0, dqx_dR[0] ); + setAtomsDerivatives (vqx,1, dqx_dR[1] ); + setAtomsDerivatives (vqx,2, dqx_dR[2] ); + setAtomsDerivatives (vqx,3, dqx_dR[3] ); + setAtomsDerivatives (vqx,4, dqx_dR[4] ); + setAtomsDerivatives (vqx,5, dqx_dR[5] ); + setBoxDerivativesNoPbc(vqx); // qy - double qy = -B/sqrt(3); + double qy = -B/sqrt(3); // qy derivatives - vector<Vector> dqy_dR(6); - for(unsigned j=0;j<6;j++){ - dqy_dR[j]=-1/sqrt(3) * dB_dR[j]; - } + vector<Vector> dqy_dR(6); + for(unsigned j=0; j<6; j++) { + dqy_dR[j]=-1/sqrt(3) * dB_dR[j]; + } - Value* vqy=getPntrToComponent("qy"); - vqy->set(qy); - setAtomsDerivatives (vqy,0, dqy_dR[0] ); - setAtomsDerivatives (vqy,1, dqy_dR[1] ); - setAtomsDerivatives (vqy,2, dqy_dR[2] ); - setAtomsDerivatives (vqy,3, dqy_dR[3] ); - setAtomsDerivatives (vqy,4, dqy_dR[4] ); - setAtomsDerivatives (vqy,5, dqy_dR[5] ); - setBoxDerivativesNoPbc(vqy); + Value* vqy=getPntrToComponent("qy"); + vqy->set(qy); + setAtomsDerivatives (vqy,0, dqy_dR[0] ); + setAtomsDerivatives (vqy,1, dqy_dR[1] ); + setAtomsDerivatives (vqy,2, dqy_dR[2] ); + setAtomsDerivatives (vqy,3, dqy_dR[3] ); + setAtomsDerivatives (vqy,4, dqy_dR[4] ); + setAtomsDerivatives (vqy,5, dqy_dR[5] ); + setBoxDerivativesNoPbc(vqy); -// qz - double qz = C/sqrt(6); +// qz + double qz = C/sqrt(6); // qz derivatives - vector<Vector> dqz_dR(6); - for(unsigned j=0;j<6;j++){ - dqz_dR[j]=1/sqrt(6) * dC_dR[j]; - } + vector<Vector> dqz_dR(6); + for(unsigned j=0; j<6; j++) { + dqz_dR[j]=1/sqrt(6) * dC_dR[j]; + } - Value* vqz=getPntrToComponent("qz"); - vqz->set(qz); - setAtomsDerivatives (vqz,0, dqz_dR[0] ); - setAtomsDerivatives (vqz,1, dqz_dR[1] ); - setAtomsDerivatives (vqz,2, dqz_dR[2] ); - setAtomsDerivatives (vqz,3, dqz_dR[3] ); - setAtomsDerivatives (vqz,4, dqz_dR[4] ); - setAtomsDerivatives (vqz,5, dqz_dR[5] ); - setBoxDerivativesNoPbc(vqz); + Value* vqz=getPntrToComponent("qz"); + vqz->set(qz); + setAtomsDerivatives (vqz,0, dqz_dR[0] ); + setAtomsDerivatives (vqz,1, dqz_dR[1] ); + setAtomsDerivatives (vqz,2, dqz_dR[2] ); + setAtomsDerivatives (vqz,3, dqz_dR[3] ); + setAtomsDerivatives (vqz,4, dqz_dR[4] ); + setAtomsDerivatives (vqz,5, dqz_dR[5] ); + setBoxDerivativesNoPbc(vqz); // PHASE - double phi=atan2(-A,B); + double phi=atan2(-A,B); // PHASE DERIVATIVES - vector<Vector> dphi_dR(6); - for(unsigned j=0;j<6;j++){ - dphi_dR[j]=1.0/(A*A+B*B) * (-B*dA_dR[j] + A*dB_dR[j]); - } + vector<Vector> dphi_dR(6); + for(unsigned j=0; j<6; j++) { + dphi_dR[j]=1.0/(A*A+B*B) * (-B*dA_dR[j] + A*dB_dR[j]); + } - Value* vphi=getPntrToComponent("phi"); - vphi->set(phi); - setAtomsDerivatives (vphi,0, dphi_dR[0] ); - setAtomsDerivatives (vphi,1, dphi_dR[1] ); - setAtomsDerivatives (vphi,2, dphi_dR[2] ); - setAtomsDerivatives (vphi,3, dphi_dR[3] ); - setAtomsDerivatives (vphi,4, dphi_dR[4] ); - setAtomsDerivatives (vphi,5, dphi_dR[5] ); - setBoxDerivativesNoPbc(vphi); + Value* vphi=getPntrToComponent("phi"); + vphi->set(phi); + setAtomsDerivatives (vphi,0, dphi_dR[0] ); + setAtomsDerivatives (vphi,1, dphi_dR[1] ); + setAtomsDerivatives (vphi,2, dphi_dR[2] ); + setAtomsDerivatives (vphi,3, dphi_dR[3] ); + setAtomsDerivatives (vphi,4, dphi_dR[4] ); + setAtomsDerivatives (vphi,5, dphi_dR[5] ); + setBoxDerivativesNoPbc(vphi); // AMPLITUDE - double amplitude=sqrt((2*(A*A+B*B)+C*C)/6); + double amplitude=sqrt((2*(A*A+B*B)+C*C)/6); // AMPLITUDE DERIVATIES - vector<Vector> damplitude_dR(6); - for (unsigned j=0;j<6;j++){ - damplitude_dR[j]=0.5*sqrt(2.0/6.0)/(sqrt(A*A+B*B+0.5*C*C)) * (2*A*dA_dR[j] + 2*B*dB_dR[j] + C*dC_dR[j]); - } + vector<Vector> damplitude_dR(6); + for (unsigned j=0; j<6; j++) { + damplitude_dR[j]=0.5*sqrt(2.0/6.0)/(sqrt(A*A+B*B+0.5*C*C)) * (2*A*dA_dR[j] + 2*B*dB_dR[j] + C*dC_dR[j]); + } - Value* vamplitude=getPntrToComponent("amplitude"); - vamplitude->set(amplitude); - setAtomsDerivatives (vamplitude,0, damplitude_dR[0] ); - setAtomsDerivatives (vamplitude,1, damplitude_dR[1] ); - setAtomsDerivatives (vamplitude,2, damplitude_dR[2] ); - setAtomsDerivatives (vamplitude,3, damplitude_dR[3] ); - setAtomsDerivatives (vamplitude,4, damplitude_dR[4] ); - setAtomsDerivatives (vamplitude,5, damplitude_dR[5] ); - setBoxDerivativesNoPbc(vamplitude); + Value* vamplitude=getPntrToComponent("amplitude"); + vamplitude->set(amplitude); + setAtomsDerivatives (vamplitude,0, damplitude_dR[0] ); + setAtomsDerivatives (vamplitude,1, damplitude_dR[1] ); + setAtomsDerivatives (vamplitude,2, damplitude_dR[2] ); + setAtomsDerivatives (vamplitude,3, damplitude_dR[3] ); + setAtomsDerivatives (vamplitude,4, damplitude_dR[4] ); + setAtomsDerivatives (vamplitude,5, damplitude_dR[5] ); + setBoxDerivativesNoPbc(vamplitude); // THETA - double theta=acos( C / sqrt(2.*(A*A+B*B) +C*C ) ); + double theta=acos( C / sqrt(2.*(A*A+B*B) +C*C ) ); // THETA DERIVATIVES - vector<Vector> dtheta_dR(6); - for(unsigned j=0;j<6;j++){ - dtheta_dR[j]=1.0/(3.0*sqrt(2)*amplitude*amplitude) * (C/(sqrt(A*A+B*B)) * (A*dA_dR[j] + B*dB_dR[j]) - sqrt(A*A+B*B)*dC_dR[j]); - } - Value* vtheta=getPntrToComponent("theta"); - vtheta->set(theta); - setAtomsDerivatives (vtheta,0, dtheta_dR[0] ); - setAtomsDerivatives (vtheta,1, dtheta_dR[1] ); - setAtomsDerivatives (vtheta,2, dtheta_dR[2] ); - setAtomsDerivatives (vtheta,3, dtheta_dR[3] ); - setAtomsDerivatives (vtheta,4, dtheta_dR[4] ); - setAtomsDerivatives (vtheta,5, dtheta_dR[5] ); - setBoxDerivativesNoPbc(vtheta); + vector<Vector> dtheta_dR(6); + for(unsigned j=0; j<6; j++) { + dtheta_dR[j]=1.0/(3.0*sqrt(2)*amplitude*amplitude) * (C/(sqrt(A*A+B*B)) * (A*dA_dR[j] + B*dB_dR[j]) - sqrt(A*A+B*B)*dC_dR[j]); + } + Value* vtheta=getPntrToComponent("theta"); + vtheta->set(theta); + setAtomsDerivatives (vtheta,0, dtheta_dR[0] ); + setAtomsDerivatives (vtheta,1, dtheta_dR[1] ); + setAtomsDerivatives (vtheta,2, dtheta_dR[2] ); + setAtomsDerivatives (vtheta,3, dtheta_dR[3] ); + setAtomsDerivatives (vtheta,4, dtheta_dR[4] ); + setAtomsDerivatives (vtheta,5, dtheta_dR[5] ); + setBoxDerivativesNoPbc(vtheta); } diff --git a/src/colvar/RDC.cpp b/src/colvar/RDC.cpp index 124101b55..18db38014 100644 --- a/src/colvar/RDC.cpp +++ b/src/colvar/RDC.cpp @@ -33,16 +33,16 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { -//+PLUMEDOC COLVAR RDC +//+PLUMEDOC COLVAR RDC /* -Calculates the (Residual) Dipolar Coupling between two atoms. +Calculates the (Residual) Dipolar Coupling between two atoms. -The RDC between two atomic nuclei depends on the \f$\theta\f$ angle between -the inter-nuclear vector and the external magnetic field. In isotropic media RDCs average to zero because of the orientational -averaging, but when the rotational symmetry is broken, either through the introduction of an alignment medium or for molecules +The RDC between two atomic nuclei depends on the \f$\theta\f$ angle between +the inter-nuclear vector and the external magnetic field. In isotropic media RDCs average to zero because of the orientational +averaging, but when the rotational symmetry is broken, either through the introduction of an alignment medium or for molecules with highly anisotropic paramagnetic susceptibility, RDCs become measurable. \f[ @@ -55,8 +55,8 @@ where D_{max}=-\mu_0\gamma_1\gamma_2h/(8\pi^3r^3) \f] -that is the maximal value of the dipolar coupling for the two nuclear spins with gyromagnetic ratio \f$\gamma\f$. -\f$\mu\f$ is the magnetic constant and h is the Planck constant. +that is the maximal value of the dipolar coupling for the two nuclear spins with gyromagnetic ratio \f$\gamma\f$. +\f$\mu\f$ is the magnetic constant and h is the Planck constant. Common Gyromagnetic Ratios (C.G.S) - H(1) 26.7513 @@ -67,8 +67,8 @@ Common Gyromagnetic Ratios (C.G.S) - CN -18.2385 - CC 45.2404 -This collective variable calculates the Residual Dipolar Coupling for a set of couple of atoms using the above definition. -From the calculated RDCs and a set of experimental values it calculates either their correlation or the squared quality factor +This collective variable calculates the Residual Dipolar Coupling for a set of couple of atoms using the above definition. +From the calculated RDCs and a set of experimental values it calculates either their correlation or the squared quality factor \f[ Q^2=\frac{\sum_i(D_i-D^{exp}_i)^2}{\sum_i(D^{exp}_i)^2} @@ -76,7 +76,7 @@ Q^2=\frac{\sum_i(D_i-D^{exp}_i)^2}{\sum_i(D^{exp}_i)^2} RDCs report only on the fraction of molecules that is aligned, this means that comparing the RDCs from a single structure in a MD simulation to the experimental values is not particularly meaningfull, from this point of view it is better to compare -their correlation. The fraction of aligned molecules can be obtained by maximising the correlation between the calculated and +their correlation. The fraction of aligned molecules can be obtained by maximising the correlation between the calculated and the experimental RDCs. This fraction can be used as a scaling factor in the calculation of the RDCs in order to compare their values. The averaging of the RDCs calculated with the above definition from a standard MD should result to 0 because of the rotational diffusion, but this variable can be used to break the rotational symmetry. @@ -92,12 +92,12 @@ Additional material and examples can be also found in the tutorial \ref belfast- In the following example five N-H RDCs are defined and their correlation with respect to a set of experimental data is calculated and restrained. In addition, and only for analysis purposes, the same RDCs are calculated using a Single Value -Decomposition algorithm. +Decomposition algorithm. \verbatim RDC ... GYROM=-72.5388 -SCALE=1.0 +SCALE=1.0 ATOMS1=20,21 ATOMS2=37,38 ATOMS3=56,57 @@ -113,7 +113,7 @@ rdce: RESTRAINT ARG=nh.corr KAPPA=0. SLOPE=-25000.0 AT=1. RDC ... GYROM=-72.5388 SCALE=1.0 -SVD +SVD ATOMS1=20,21 COUPLING1=8.17 ATOMS2=37,38 COUPLING2=-8.271 ATOMS3=56,57 COUPLING3=-10.489 @@ -125,7 +125,7 @@ LABEL=svd PRINT ARG=nh.corr,rdce.bias FILE=colvar PRINT ARG=svd.* FILE=svd \endverbatim -(See also \ref PRINT, \ref RESTRAINT) +(See also \ref PRINT, \ref RESTRAINT) */ //+ENDPLUMEDOC @@ -146,55 +146,55 @@ public: PLUMED_REGISTER_ACTION(RDC,"RDC") -void RDC::registerKeywords( Keywords& keys ){ +void RDC::registerKeywords( Keywords& keys ) { Colvar::registerKeywords( keys ); componentsAreNotOptional(keys); useCustomisableComponents(keys); keys.add("numbered","ATOMS","the couple of atoms involved in each of the bonds for which you wish to calculate the RDC. " - "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one dipolar coupling will be " - "calculated for each ATOMS keyword you specify."); + "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one dipolar coupling will be " + "calculated for each ATOMS keyword you specify."); keys.reset_style("ATOMS","atoms"); keys.add("compulsory","GYROM","Add the product of the gyromagnetic constants for the bond. "); keys.add("compulsory","SCALE","Add the scaling factor to take into account concentration and other effects. "); - keys.addFlag("SVD",false,"Set to TRUE if you want to backcalculate using Single Value Decomposition (need GSL at compilation time)."); - keys.addFlag("ADDCOUPLINGS",false,"Set to TRUE if you want to have fixed components with the experimetnal values."); + keys.addFlag("SVD",false,"Set to TRUE if you want to backcalculate using Single Value Decomposition (need GSL at compilation time)."); + keys.addFlag("ADDCOUPLINGS",false,"Set to TRUE if you want to have fixed components with the experimetnal values."); keys.add("numbered","COUPLING","Add an experimental value for each coupling (needed by SVD and usefull for \ref STATS)."); keys.addOutputComponent("rdc","default","the calculated # RDC"); keys.addOutputComponent("exp","SVD/ADDCOUPLINGS","the experimental # RDC"); } RDC::RDC(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao), -Const(0.3356806), -mu_s(0), -scale(1), -pbc(true) + PLUMED_COLVAR_INIT(ao), + Const(0.3356806), + mu_s(0), + scale(1), + pbc(true) { bool nopbc=!pbc; parseFlag("NOPBC",nopbc); - pbc=!nopbc; + pbc=!nopbc; // Read in the atoms vector<AtomNumber> t, atoms; - for(int i=1;;++i ){ - parseAtomList("ATOMS", i, t ); - if( t.empty() ) break; - if( t.size()!=2 ){ - std::string ss; Tools::convert(i,ss); - error("ATOMS" + ss + " keyword has the wrong number of atoms"); - } - atoms.push_back(t[0]); - atoms.push_back(t[1]); - t.resize(0); + for(int i=1;; ++i ) { + parseAtomList("ATOMS", i, t ); + if( t.empty() ) break; + if( t.size()!=2 ) { + std::string ss; Tools::convert(i,ss); + error("ATOMS" + ss + " keyword has the wrong number of atoms"); + } + atoms.push_back(t[0]); + atoms.push_back(t[1]); + t.resize(0); } const unsigned ndata = atoms.size()/2; - + // Read in GYROMAGNETIC constants parse("GYROM", mu_s); if(mu_s==0.) error("GYROM must be set"); - // Read in SCALING factors + // Read in SCALING factors parse("SCALE", scale); if(scale==0.) error("SCALE must be different from 0"); @@ -208,19 +208,19 @@ pbc(true) parseFlag("ADDCOUPLINGS",addcoupling); if(svd||addcoupling) { - coupl.resize( ndata ); + coupl.resize( ndata ); unsigned ntarget=0; - for(unsigned i=0;i<ndata;++i){ - if( !parseNumbered( "COUPLING", i+1, coupl[i] ) ) break; - ntarget++; + for(unsigned i=0; i<ndata; ++i) { + if( !parseNumbered( "COUPLING", i+1, coupl[i] ) ) break; + ntarget++; } if( ntarget!=ndata ) error("found wrong number of COUPLING values"); } - // Ouput details of all contacts + // Ouput details of all contacts log.printf(" Gyromagnetic moment is %f. Scaling factor is %f.",mu_s,scale); - for(unsigned i=0;i<ndata;++i){ - log.printf(" The %uth Bond Dipolar Coupling is calculated from atoms : %d %d.", i+1, atoms[2*i].serial(), atoms[2*i+1].serial()); + for(unsigned i=0; i<ndata; ++i) { + log.printf(" The %uth Bond Dipolar Coupling is calculated from atoms : %d %d.", i+1, atoms[2*i].serial(), atoms[2*i+1].serial()); if(svd||addcoupling) log.printf(" Experimental coupling is %f.", coupl[i]); log.printf("\n"); } @@ -231,7 +231,7 @@ pbc(true) checkRead(); - for(unsigned i=0;i<ndata;i++) { + for(unsigned i=0; i<ndata; i++) { std::string num; Tools::convert(i,num); if(!svd) { addComponentWithDerivatives("rdc_"+num); @@ -243,7 +243,7 @@ pbc(true) } if(svd||addcoupling) { - for(unsigned i=0;i<ndata;i++) { + for(unsigned i=0; i<ndata; i++) { std::string num; Tools::convert(i,num); addComponent("exp_"+num); componentIsNotPeriodic("exp_"+num); @@ -260,7 +260,7 @@ void RDC::calculate() const double max = -Const*scale*mu_s; const unsigned N=getNumberOfAtoms(); /* RDC Calculations and forces */ - for(unsigned r=0;r<N;r+=2) + for(unsigned r=0; r<N; r+=2) { const unsigned index=r/2; Vector distance; @@ -268,7 +268,7 @@ void RDC::calculate() else distance = delta(getPosition(r),getPosition(r+1)); const double d = distance.modulo(); const double ind = 1./d; - const double id3 = ind*ind*ind; + const double id3 = ind*ind*ind; const double dmax = id3*max; const double cos_theta = distance[2]*ind; @@ -289,8 +289,8 @@ void RDC::calculate() Value* val=getPntrToComponent(index); val->set(rdc); setBoxDerivatives(val, Tensor(distance,dRDC)); - setAtomsDerivatives(val, r , dRDC); - setAtomsDerivatives(val, r+1, -dRDC); + setAtomsDerivatives(val, r, dRDC); + setAtomsDerivatives(val, r+1, -dRDC); } } else { @@ -317,7 +317,7 @@ void RDC::calculate() double d = distance.modulo(); double d2 = d*d; double d3 = d2*d; - double id3 = 1./d3; + double id3 = 1./d3; double max = -Const*mu_s*scale; dmax[index] = id3*max; double mu_x = distance[0]/d; @@ -334,7 +334,7 @@ void RDC::calculate() gsl_matrix_memcpy(A,coef_mat); gsl_linalg_SV_decomp(A, V, Stmp, work); gsl_linalg_SV_solve(A, V, Stmp, rdc_vec, S); - /* tensor + /* tensor double Sxx = gsl_vector_get(S,0); double Syy = gsl_vector_get(S,1); double Szz = -Sxx-Syy; diff --git a/src/colvar/RMSD.cpp b/src/colvar/RMSD.cpp index 642433452..8801dfeed 100644 --- a/src/colvar/RMSD.cpp +++ b/src/colvar/RMSD.cpp @@ -30,15 +30,15 @@ using namespace std; -namespace PLMD{ -namespace colvar{ - +namespace PLMD { +namespace colvar { + class RMSD : public Colvar { - + MultiValue myvals; ReferenceValuePack mypack; PLMD::RMSDBase* rmsd; - bool squared; + bool squared; public: explicit RMSD(const ActionOptions&); @@ -52,30 +52,30 @@ using namespace std; //+PLUMEDOC DCOLVAR RMSD /* -Calculate the RMSD with respect to a reference structure. +Calculate the RMSD with respect to a reference structure. The aim with this colvar it to calculate something like: \f[ -d(X,X') = \vert X-X' \vert +d(X,X') = \vert X-X' \vert \f] -where \f$ X \f$ is the instantaneous position of all the atoms in the system and +where \f$ X \f$ is the instantaneous position of all the atoms in the system and \f$ X' \f$ is the positions of the atoms in some reference structure provided as input. \f$ d(X,X') \f$ thus measures the distance all the atoms have moved away from this reference configuration. -Oftentimes, it is only the internal motions of the structure - i.e. not the translations of the center of +Oftentimes, it is only the internal motions of the structure - i.e. not the translations of the center of mass or the rotations of the reference frame - that are interesting. Hence, when calculating the the root-mean-square deviation between the atoms in two configurations you must first superimpose the two structures in some way. At present PLUMED provides two distinct ways -of performing this superposition. The first method is applied when you use TYPE=SIMPLE in the input +of performing this superposition. The first method is applied when you use TYPE=SIMPLE in the input line. This instruction tells PLUMED that the root mean square deviation is to be calculated after the positions of the geometric centers in the reference and instantaneous configurations are aligned. In -other words \f$d(X,x')\f$ is to be calculated using: +other words \f$d(X,x')\f$ is to be calculated using: \f[ - d(X,X') = \sqrt{ \sum_i \sum_\alpha^{x,y,z} \frac{w_i}{\sum_j w_j}( X_{i,\alpha}-com_\alpha(X)-{X'}_{i,\alpha}+com_\alpha(X') )^2 } + d(X,X') = \sqrt{ \sum_i \sum_\alpha^{x,y,z} \frac{w_i}{\sum_j w_j}( X_{i,\alpha}-com_\alpha(X)-{X'}_{i,\alpha}+com_\alpha(X') )^2 } \f] -with +with \f[ com_\alpha(X)= \sum_i \frac{w'_{i}}{\sum_j w'_j}X_{i,\alpha} \f] @@ -86,42 +86,42 @@ com_\alpha(X')= \sum_i \frac{w'_{i}}{\sum_j w'_j}X'_{i,\alpha} Obviously, \f$ com_\alpha(X) \f$ and \f$ com_\alpha(X') \f$ represent the positions of the center of mass in the reference and instantaneous configurations if the weights $w'$ are set equal to the atomic masses. If the weights are all set equal to one, however, \f$com_\alpha(X) \f$ and \f$ com_\alpha(X') \f$ are the positions of the geometric centers. -Notice that there are sets of weights: \f$ w' \f$ and \f$ w \f$. The first is used to calculate the position of the center of mass +Notice that there are sets of weights: \f$ w' \f$ and \f$ w \f$. The first is used to calculate the position of the center of mass (so it determines how the atoms are \e aligned). Meanwhile, the second is used when calculating how far the atoms have actually been \e displaced. These weights are assigned in the reference configuration that you provide as input (i.e. the appear in the input file -to this action that you set using REFERENCE=whatever.pdb). This input reference configuration consists of a simple pdb file -containing the set of atoms for which you want to calculate the RMSD displacement and their positions in the reference configuration. -It is important to note that the indices in this pdb need to be set correctly. The indices in this file determine the indices of the +to this action that you set using REFERENCE=whatever.pdb). This input reference configuration consists of a simple pdb file +containing the set of atoms for which you want to calculate the RMSD displacement and their positions in the reference configuration. +It is important to note that the indices in this pdb need to be set correctly. The indices in this file determine the indices of the instantaneous atomic positions that are used by PLUMED when calculating this colvar. As such if you want to calculate the RMSD distance moved by the 1st, 4th, 6th and 28th atoms in the MD codes input file then the indices of the corresponding refernece positions in this pdb -file should be set equal to 1, 4, 6 and 28. +file should be set equal to 1, 4, 6 and 28. -The pdb input file should also contain the values of \f$w\f$ and \f$w'\f$. In particular, the OCCUPANCY column (the first column after the coordinates) +The pdb input file should also contain the values of \f$w\f$ and \f$w'\f$. In particular, the OCCUPANCY column (the first column after the coordinates) is used provides the values of \f$ w'\f$ that are used to calculate the position of the centre of mass. The BETA column (the second column -after the Cartesian coordinates) is used to provide the \f$ w \f$ values which are used in the the calculation of the displacement. -Please note that it is possible to use fractional values for beta and for the occupancy. However, we recommend you only do this when -you really know what you are doing however as the results can be rather strange. +after the Cartesian coordinates) is used to provide the \f$ w \f$ values which are used in the the calculation of the displacement. +Please note that it is possible to use fractional values for beta and for the occupancy. However, we recommend you only do this when +you really know what you are doing however as the results can be rather strange. -In PDB files the atomic coordinates and box lengths should be in Angstroms unless -you are working with natural units. If you are working with natural units then the coordinates +In PDB files the atomic coordinates and box lengths should be in Angstroms unless +you are working with natural units. If you are working with natural units then the coordinates should be in your natural length unit. For more details on the PDB file format visit http://www.wwpdb.org/docs.html. -A different method is used to calculate the RMSD distance when you use TYPE=OPTIMAL on the input line. In this case the root mean square +A different method is used to calculate the RMSD distance when you use TYPE=OPTIMAL on the input line. In this case the root mean square deviation is calculated after the positions of geometric centers in the reference and instantaneous configurations are aligned AND after an optimal alignment of the two frames is performed so that motion due to rotation of the reference frame between the two structures is removed. The equation for \f$d(X,X')\f$ in this case reads: \f[ -d(X,X') = \sqrt{ \sum_i \sum_\alpha^{x,y,z} \frac{w_i}{\sum_j w_j}[ X_{i,\alpha}-com_\alpha(X)- \sum_\beta M(X,X',w')_{\alpha,\beta}({X'}_{i,\beta}-com_\beta(X')) ]^2 } +d(X,X') = \sqrt{ \sum_i \sum_\alpha^{x,y,z} \frac{w_i}{\sum_j w_j}[ X_{i,\alpha}-com_\alpha(X)- \sum_\beta M(X,X',w')_{\alpha,\beta}({X'}_{i,\beta}-com_\beta(X')) ]^2 } \f] -where \f$ M(X,X',w') \f$ is the optimal alignment matrix which is calculated using the Kearsley \cite kearsley algorithm. Again different sets of +where \f$ M(X,X',w') \f$ is the optimal alignment matrix which is calculated using the Kearsley \cite kearsley algorithm. Again different sets of weights are used for the alignment (\f$w'\f$) and for the displacement calcuations (\f$w\f$). -This gives a great deal of flexibility as it allows you to use a different sets of atoms (which may or may not overlap) for the alignment and displacement +This gives a great deal of flexibility as it allows you to use a different sets of atoms (which may or may not overlap) for the alignment and displacement parts of the calculation. This may be very useful when you want to calculate how a ligand moves about in a protein cavity as you can use the protein as a reference -system and do no alignment of the ligand. +system and do no alignment of the ligand. -(Note: when this form of RMSD is used to calculate the secondary structure variables (\ref ALPHARMSD, \ref ANTIBETARMSD and \ref PARABETARMSD +(Note: when this form of RMSD is used to calculate the secondary structure variables (\ref ALPHARMSD, \ref ANTIBETARMSD and \ref PARABETARMSD all the atoms in the segment are assumed to be part of both the alignment and displacement sets and all weights are set equal to one) Please note that there are a number of other methods for calculating the distance between the instantaneous configuration and a reference configuration @@ -144,7 +144,7 @@ RMSD REFERENCE=file.pdb TYPE=OPTIMAL PLUMED_REGISTER_ACTION(RMSD,"RMSD") -void RMSD::registerKeywords(Keywords& keys){ +void RMSD::registerKeywords(Keywords& keys) { Colvar::registerKeywords(keys); keys.add("compulsory","REFERENCE","a file in pdb format containing the reference structure and the atoms involved in the CV."); keys.add("compulsory","TYPE","SIMPLE","the manner in which RMSD alignment is performed. Should be OPTIMAL or SIMPLE."); @@ -153,11 +153,11 @@ void RMSD::registerKeywords(Keywords& keys){ } RMSD::RMSD(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao),myvals(1,0), mypack(0,0,myvals),squared(false) + PLUMED_COLVAR_INIT(ao),myvals(1,0), mypack(0,0,myvals),squared(false) { string reference; parse("REFERENCE",reference); - string type; + string type; type.assign("SIMPLE"); parse("TYPE",type); parseFlag("SQUARED",squared); @@ -170,10 +170,10 @@ PLUMED_COLVAR_INIT(ao),myvals(1,0), mypack(0,0,myvals),squared(false) // read everything in ang and transform to nm if we are not in natural units if( !pdb.read(reference,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength()) ) - error("missing input file " + reference ); + error("missing input file " + reference ); rmsd = metricRegister().create<RMSDBase>(type,pdb); - + std::vector<AtomNumber> atoms; rmsd->getAtomRequests( atoms ); // rmsd->setNumberOfAtoms( atoms.size() ); @@ -181,7 +181,7 @@ PLUMED_COLVAR_INIT(ao),myvals(1,0), mypack(0,0,myvals),squared(false) // Setup the derivative pack myvals.resize( 1, 3*atoms.size()+9 ); mypack.resize( 0, atoms.size() ); - for(unsigned i=0;i<atoms.size();++i) mypack.setAtomIndex( i, i ); + for(unsigned i=0; i<atoms.size(); ++i) mypack.setAtomIndex( i, i ); log.printf(" reference from file %s\n",reference.c_str()); log.printf(" which contains %d atoms\n",getNumberOfAtoms()); @@ -189,17 +189,17 @@ PLUMED_COLVAR_INIT(ao),myvals(1,0), mypack(0,0,myvals),squared(false) if(squared)log.printf(" chosen to use SQUARED option for MSD instead of RMSD\n"); } -RMSD::~RMSD(){ +RMSD::~RMSD() { delete rmsd; } // calculator -void RMSD::calculate(){ +void RMSD::calculate() { double r=rmsd->calculate( getPositions(), mypack, squared ); - setValue(r); - for(unsigned i=0;i<getNumberOfAtoms();i++) setAtomsDerivatives( i, mypack.getAtomDerivative(i) ); + setValue(r); + for(unsigned i=0; i<getNumberOfAtoms(); i++) setAtomsDerivatives( i, mypack.getAtomDerivative(i) ); Tensor virial; plumed_dbg_assert( !mypack.virialWasSet() ); setBoxDerivativesNoPbc(); diff --git a/src/colvar/Template.cpp b/src/colvar/Template.cpp index c034d89d7..85cb95d27 100644 --- a/src/colvar/Template.cpp +++ b/src/colvar/Template.cpp @@ -27,8 +27,8 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { //+PLUMEDOC COLVAR TEMPLATE /* @@ -41,7 +41,7 @@ This file provides a template for if you want to introduce a new CV. <!---You should put an example of how to use your CV here---> \verbatim -# This should be a sample input. +# This should be a sample input. t: TEMPLATE ATOMS=1,2 PRINT ARG=t STRIDE=100 FILE=COLVAR \endverbatim @@ -50,7 +50,7 @@ PRINT ARG=t STRIDE=100 FILE=COLVAR */ //+ENDPLUMEDOC - + class Template : public Colvar { bool pbc; @@ -63,7 +63,7 @@ public: PLUMED_REGISTER_ACTION(Template,"TEMPLATE") -void Template::registerKeywords(Keywords& keys){ +void Template::registerKeywords(Keywords& keys) { Colvar::registerKeywords(keys); keys.addFlag("TEMPLATE_DEFAULT_OFF_FLAG",false,"flags that are by default not performed should be specified like this"); keys.addFlag("TEMPLATE_DEFAULT_ON_FLAG",true,"flags that are by default performed should be specified like this"); @@ -73,8 +73,8 @@ void Template::registerKeywords(Keywords& keys){ } Template::Template(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao), -pbc(true) + PLUMED_COLVAR_INIT(ao), + pbc(true) { vector<AtomNumber> atoms; parseAtomList("ATOMS",atoms); @@ -96,10 +96,10 @@ pbc(true) // calculator -void Template::calculate(){ +void Template::calculate() { Vector distance; - if(pbc){ + if(pbc) { distance=pbcDistance(getPosition(0),getPosition(1)); } else { distance=delta(getPosition(0),getPosition(1)); diff --git a/src/colvar/Torsion.cpp b/src/colvar/Torsion.cpp index 7d885295f..274d0565a 100644 --- a/src/colvar/Torsion.cpp +++ b/src/colvar/Torsion.cpp @@ -28,8 +28,8 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { //+PLUMEDOC COLVAR TORSION /* @@ -37,7 +37,7 @@ Calculate a torsional angle. This command can be used to compute the torsion between four atoms or alternatively to calculate the angle between two vectors projected on the plane -orthogonal to an axis. +orthogonal to an axis. \par Examples @@ -51,7 +51,7 @@ PRINT ARG=t FILE=COLVAR \endverbatim If you are working with a protein you can specify the special named torsion angles \f$\phi\f$, \f$\psi\f$, \f$\omega\f$ and \f$\chi_1\f$ -by using TORSION in combination with the \ref MOLINFO command. This can be done by using the following +by using TORSION in combination with the \ref MOLINFO command. This can be done by using the following syntax. \verbatim @@ -65,7 +65,7 @@ Here, \@phi-3 tells plumed that you would like to calculate the \f$\phi\f$ angle Similarly \@psi-4 tells plumed that you want to calculate the \f$\psi\f$ angle of the 4th residue of the protein. */ //+ENDPLUMEDOC - + class Torsion : public Colvar { bool pbc; bool do_cosine; @@ -79,19 +79,19 @@ public: PLUMED_REGISTER_ACTION(Torsion,"TORSION") -void Torsion::registerKeywords(Keywords& keys){ - Colvar::registerKeywords( keys ); - keys.add("atoms-1","ATOMS","the four atoms involved in the torsional angle"); - keys.add("atoms-2","AXIS","two atoms that define an axis. You can use this to find the angle in the plane perpendicular to the axis between the vectors specified using the VECTOR1 and VECTOR2 keywords."); - keys.add("atoms-2","VECTOR1","two atoms that define a vector. You can use this in combination with VECTOR2 and AXIS"); - keys.add("atoms-2","VECTOR2","two atoms that define a vector. You can use this in combination with VECTOR1 and AXIS"); - keys.addFlag("COSINE",false,"calculate cosine instead of dihedral"); +void Torsion::registerKeywords(Keywords& keys) { + Colvar::registerKeywords( keys ); + keys.add("atoms-1","ATOMS","the four atoms involved in the torsional angle"); + keys.add("atoms-2","AXIS","two atoms that define an axis. You can use this to find the angle in the plane perpendicular to the axis between the vectors specified using the VECTOR1 and VECTOR2 keywords."); + keys.add("atoms-2","VECTOR1","two atoms that define a vector. You can use this in combination with VECTOR2 and AXIS"); + keys.add("atoms-2","VECTOR2","two atoms that define a vector. You can use this in combination with VECTOR1 and AXIS"); + keys.addFlag("COSINE",false,"calculate cosine instead of dihedral"); } Torsion::Torsion(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao), -pbc(true), -do_cosine(false) + PLUMED_COLVAR_INIT(ao), + pbc(true), + do_cosine(false) { vector<AtomNumber> atoms,v1,v2,axis; parseAtomList("ATOMS",atoms); @@ -106,7 +106,7 @@ do_cosine(false) pbc=!nopbc; checkRead(); - if(atoms.size()==4){ + if(atoms.size()==4) { if(!(v1.empty() && v2.empty() && axis.empty())) error("ATOMS keyword is not compatible with VECTOR1, VECTOR2 and AXIS keywords"); log.printf(" between atoms %d %d %d %d\n",atoms[0].serial(),atoms[1].serial(),atoms[2].serial(),atoms[3].serial()); @@ -115,11 +115,11 @@ do_cosine(false) atoms[4]=atoms[2]; atoms[3]=atoms[2]; atoms[2]=atoms[1]; - }else if(atoms.empty()){ + } else if(atoms.empty()) { if(!(v1.size()==2 && v2.size()==2 && axis.size()==2)) error("VECTOR1, VECTOR2 and AXIS should specify 2 atoms each"); log.printf(" between lines %d-%d and %d-%d, projected on the plane orthogonal to line %d-%d\n", - v1[0].serial(),v1[1].serial(),v2[0].serial(),v2[1].serial(),axis[0].serial(),axis[1].serial()); + v1[0].serial(),v1[1].serial(),v2[0].serial(),v2[1].serial(),axis[0].serial(),axis[1].serial()); atoms.resize(6); atoms[0]=v1[1]; atoms[1]=v1[0]; @@ -127,7 +127,7 @@ do_cosine(false) atoms[3]=axis[1]; atoms[4]=v2[0]; atoms[5]=v2[1]; - }else error("ATOMS should specify 4 atoms"); + } else error("ATOMS should specify 4 atoms"); if(pbc) log.printf(" using periodic boundary conditions\n"); else log.printf(" without periodic boundary conditions\n"); @@ -141,7 +141,7 @@ do_cosine(false) } // calculator -void Torsion::calculate(){ +void Torsion::calculate() { Vector d0,d1,d2; if(pbc) makeWhole(); @@ -151,11 +151,11 @@ void Torsion::calculate(){ Vector dd0,dd1,dd2; PLMD::Torsion t; double torsion=t.compute(d0,d1,d2,dd0,dd1,dd2); - if(do_cosine){ - dd0 *= -sin(torsion); - dd1 *= -sin(torsion); - dd2 *= -sin(torsion); - torsion = cos(torsion); + if(do_cosine) { + dd0 *= -sin(torsion); + dd1 *= -sin(torsion); + dd2 *= -sin(torsion); + torsion = cos(torsion); } setAtomsDerivatives(0,dd0); setAtomsDerivatives(1,-dd0); diff --git a/src/colvar/Volume.cpp b/src/colvar/Volume.cpp index b33652d66..7b4fb9aac 100644 --- a/src/colvar/Volume.cpp +++ b/src/colvar/Volume.cpp @@ -27,8 +27,8 @@ using namespace std; -namespace PLMD{ -namespace colvar{ +namespace PLMD { +namespace colvar { //+PLUMEDOC COLVAR VOLUME /* @@ -59,7 +59,7 @@ public: PLUMED_REGISTER_ACTION(Volume,"VOLUME") Volume::Volume(const ActionOptions&ao): -PLUMED_COLVAR_INIT(ao) + PLUMED_COLVAR_INIT(ao) { std::vector<AtomNumber> atoms; checkRead(); @@ -68,7 +68,7 @@ PLUMED_COLVAR_INIT(ao) requestAtoms(atoms); } -void Volume::registerKeywords( Keywords& keys ){ +void Volume::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionWithValue::registerKeywords( keys ); ActionAtomistic::registerKeywords( keys ); @@ -76,7 +76,7 @@ void Volume::registerKeywords( Keywords& keys ){ // calculator -void Volume::calculate(){ +void Volume::calculate() { double v=getBox().determinant(); setBoxDerivatives(-v*Tensor::identity()); diff --git a/src/config/Config.h b/src/config/Config.h index 95501d9ef..39c441e98 100644 --- a/src/config/Config.h +++ b/src/config/Config.h @@ -24,8 +24,8 @@ #include <string> -namespace PLMD{ -namespace config{ +namespace PLMD { +namespace config { /// Return the extension of shared libraries on this system. /// It is either "so" or "dylib". In case shared libraries are disabled, it returns an empty string. diff --git a/src/config/Config.inc.in b/src/config/Config.inc.in index 03eb4af41..659689558 100644 --- a/src/config/Config.inc.in +++ b/src/config/Config.inc.in @@ -25,18 +25,18 @@ #include <cstdlib> #include <cstring> -namespace PLMD{ -namespace config{ +namespace PLMD { +namespace config { -std::string getSoExt(){ +std::string getSoExt() { return "@SOEXT@"; } -bool isInstalled(){ +bool isInstalled() { return @ISINSTALLED@; } -std::string getPlumedRoot(){ +std::string getPlumedRoot() { char *env = std::getenv("PLUMED_ROOT"); std::string ss; if( env == NULL) { @@ -47,7 +47,7 @@ std::string getPlumedRoot(){ return ss; } -std::string getPlumedHtmldir(){ +std::string getPlumedHtmldir() { if(!isInstalled()) return getPlumedRoot(); char *env = std::getenv("PLUMED_HTMLDIR"); std::string ss; @@ -59,7 +59,7 @@ std::string getPlumedHtmldir(){ return ss; } -std::string getPlumedIncludedir(){ +std::string getPlumedIncludedir() { if(!isInstalled()) return getPlumedRoot()+"/include"; char *env = std::getenv("PLUMED_INCLUDEDIR"); std::string ss; @@ -71,7 +71,7 @@ std::string getPlumedIncludedir(){ return ss; } -std::string getPlumedProgramName(){ +std::string getPlumedProgramName() { if(!isInstalled()) return "plumed"; char *env = std::getenv("PLUMED_PROGRAM_NAME"); std::string ss; @@ -83,86 +83,87 @@ std::string getPlumedProgramName(){ return ss; } -std::string getEnvCommand(){ +std::string getEnvCommand() { return "env PLUMED_ROOT=\""+getPlumedRoot()+"\""+ - " env PLUMED_HTMLDIR=\""+getPlumedHtmldir()+"\""+ - " env PLUMED_INCLUDEDIR=\""+getPlumedIncludedir()+"\""+ - " env PLUMED_PROGRAM_NAME=\""+getPlumedProgramName()+"\""+ - " env PLUMED_IS_INSTALLED=\""+(@ISINSTALLED@?"yes":"no")+"\""; + " env PLUMED_HTMLDIR=\""+getPlumedHtmldir()+"\""+ + " env PLUMED_INCLUDEDIR=\""+getPlumedIncludedir()+"\""+ + " env PLUMED_PROGRAM_NAME=\""+getPlumedProgramName()+"\""+ + " env PLUMED_IS_INSTALLED=\""+(@ISINSTALLED@?"yes":"no")+"\""; } -std::string getVersion(){ +std::string getVersion() { return PLUMED_VERSION_SHORT; } -std::string getVersionLong(){ +std::string getVersionLong() { return PLUMED_VERSION_LONG; } -std::string getVersionGit(){ +std::string getVersionGit() { return PLUMED_VERSION_GIT; } -std::string getMakefile(){ - static const char conf [] ={ +std::string getMakefile() { + static const char conf [] = { #include "Makefile.conf.xxd" - , 0x00 }; + , 0x00 + }; return std::string(conf,conf+std::strlen(conf)); } -bool hasMatheval(){ +bool hasMatheval() { #if __PLUMED_HAS_MATHEVAL - return true; + return true; #else - return false; + return false; #endif } -bool hasDlopen(){ +bool hasDlopen() { #if __PLUMED_HAS_DLOPEN - return true; + return true; #else - return false; + return false; #endif } -bool hasCregex(){ +bool hasCregex() { #if __PLUMED_HAS_CREGEX - return true; + return true; #else - return false; + return false; #endif } -bool hasMolfile(){ +bool hasMolfile() { #if __PLUMED_HAS_MOLFILE_PLUGINS - return true; + return true; #else - return false; + return false; #endif } -bool hasExternalMolfile(){ +bool hasExternalMolfile() { #if __PLUMED_HAS_EXTERNAL_MOLFILE_PLUGINS - return true; + return true; #else - return false; + return false; #endif } -bool hasZlib(){ +bool hasZlib() { #if __PLUMED_HAS_ZLIB - return true; + return true; #else - return false; + return false; #endif } -bool hasXdrfile(){ +bool hasXdrfile() { #if __PLUMED_HAS_XDRFILE - return true; + return true; #else - return false; + return false; #endif } diff --git a/src/core/Action.cpp b/src/core/Action.cpp index 1c4782009..a78c7c730 100644 --- a/src/core/Action.cpp +++ b/src/core/Action.cpp @@ -28,25 +28,25 @@ #include "ActionSet.h" #include <iostream> -namespace PLMD{ +namespace PLMD { Keywords ActionOptions::emptyKeys; ActionOptions::ActionOptions(PlumedMain&p,const std::vector<std::string>&l): -plumed(p), -line(l), -keys(emptyKeys) + plumed(p), + line(l), + keys(emptyKeys) { } ActionOptions::ActionOptions(const ActionOptions&ao,const Keywords&keys): -plumed(ao.plumed), -line(ao.line), -keys(keys) + plumed(ao.plumed), + line(ao.line), + keys(keys) { } -void Action::registerKeywords( Keywords& keys ){ +void Action::registerKeywords( Keywords& keys ) { plumed_assert( keys.size()==0 ); keys.add( "hidden", "LABEL", "a label for the action so that its output can be referenced in the input to other actions. Actions with scalar output are referenced using their label only. Actions with vector output must have a separate label for every component. Individual componets are then refered to using label.component" ); keys.reserve("optional","UPDATE_FROM","Only update this action from this time"); @@ -71,14 +71,14 @@ Action::Action(const ActionOptions&ao): line.erase(line.begin()); log.printf("Action %s\n",name.c_str()); - if(comm.Get_rank()==0){ + if(comm.Get_rank()==0) { replica_index=multi_sim_comm.Get_rank(); } comm.Bcast(replica_index,0); - if ( keywords.exists("LABEL") ){ parse("LABEL",label); } + if ( keywords.exists("LABEL") ) { parse("LABEL",label); } - if(label.length()==0){ + if(label.length()==0) { std::string s; Tools::convert(plumed.getActionSet().size(),s); label="@"+s; } @@ -88,7 +88,7 @@ Action::Action(const ActionOptions&ao): if(update_from!=std::numeric_limits<double>::max()) log.printf(" only update from time %f\n",update_from); if ( keywords.exists("UPDATE_UNTIL") ) parse("UPDATE_UNTIL",update_until); if(update_until!=std::numeric_limits<double>::max()) log.printf(" only update until time %f\n",update_until); - if ( keywords.exists("RESTART") ){ + if ( keywords.exists("RESTART") ) { std::string srestart="AUTO"; parse("RESTART",srestart); if(srestart=="YES") restart=true; @@ -98,15 +98,15 @@ Action::Action(const ActionOptions&ao): } } -Action::~Action(){ - if(files.size()!=0){ +Action::~Action() { + if(files.size()!=0) { std::cerr<<"WARNING: some files open in action "+getLabel()+" where not properly closed. This could lead to data loss!!\n"; } } -FILE* Action::fopen(const char *path, const char *mode){ +FILE* Action::fopen(const char *path, const char *mode) { bool write(false); - for(const char*p=mode;*p;p++) if(*p=='w' || *p=='a' || *p=='+') write=true; + for(const char*p=mode; *p; p++) if(*p=='w' || *p=='a' || *p=='+') write=true; FILE* fp; if(write && comm.Get_rank()!=0) fp=plumed.fopen("/dev/null",mode); else fp=plumed.fopen(path,mode); @@ -114,64 +114,64 @@ FILE* Action::fopen(const char *path, const char *mode){ return fp; } -int Action::fclose(FILE*fp){ +int Action::fclose(FILE*fp) { files.erase(fp); return plumed.fclose(fp); } -void Action::fflush(){ - for(const auto & p : files){ +void Action::fflush() { + for(const auto & p : files) { std::fflush(p); } } -std::string Action::getKeyword(const std::string& key){ - // Check keyword has been registered +std::string Action::getKeyword(const std::string& key) { + // Check keyword has been registered plumed_massert(keywords.exists(key), "keyword " + key + " has not been registered"); std::string outkey; if( Tools::getKey(line,key,outkey ) ) return key + outkey; - if( keywords.style(key,"compulsory") ){ - if( keywords.getDefaultValue(key,outkey) ){ - if( outkey.length()==0 ) error("keyword " + key + " has weird default value"); - return key + "=" + outkey; - } else { - error("keyword " + key + " is compulsory for this action"); - } - } + if( keywords.style(key,"compulsory") ) { + if( keywords.getDefaultValue(key,outkey) ) { + if( outkey.length()==0 ) error("keyword " + key + " has weird default value"); + return key + "=" + outkey; + } else { + error("keyword " + key + " is compulsory for this action"); + } + } return ""; } -void Action::parseFlag(const std::string&key,bool & t){ +void Action::parseFlag(const std::string&key,bool & t) { // Check keyword has been registered plumed_massert(keywords.exists(key), "keyword " + key + " has not been registered"); // Check keyword is a flag - if(!keywords.style(key,"nohtml")){ - plumed_massert( keywords.style(key,"vessel") || keywords.style(key,"flag") || keywords.style(key,"hidden"), "keyword " + key + " is not a flag"); + if(!keywords.style(key,"nohtml")) { + plumed_massert( keywords.style(key,"vessel") || keywords.style(key,"flag") || keywords.style(key,"hidden"), "keyword " + key + " is not a flag"); } // Read in the flag otherwise get the default value from the keywords object - if(!Tools::parseFlag(line,key,t)){ - if( keywords.style(key,"nohtml") || keywords.style(key,"vessel") ){ - t=false; - } else if ( !keywords.getLogicalDefault(key,t) ){ - log.printf("ERROR in action %s with label %s : flag %s has no default",name.c_str(),label.c_str(),key.c_str() ); - plumed_error(); - } + if(!Tools::parseFlag(line,key,t)) { + if( keywords.style(key,"nohtml") || keywords.style(key,"vessel") ) { + t=false; + } else if ( !keywords.getLogicalDefault(key,t) ) { + log.printf("ERROR in action %s with label %s : flag %s has no default",name.c_str(),label.c_str(),key.c_str() ); + plumed_error(); + } } } -void Action::addDependency(Action*action){ +void Action::addDependency(Action*action) { after.push_back(action); } -void Action::activate(){ +void Action::activate() { // preparation step is called only the first time an Action is activated. // since it could change its dependences (e.g. in an ActionAtomistic which is // accessing to a virtual atom), this is done just before dependencies are // activated - if(!active){ + if(!active) { this->unlockRequests(); prepare(); this->lockRequests(); @@ -180,57 +180,57 @@ void Action::activate(){ active=true; } -void Action::setOption(const std::string &s){ -// This overloads the action and activate some options +void Action::setOption(const std::string &s) { +// This overloads the action and activate some options options.insert(s); for(const auto & p : after) p->setOption(s); } -void Action::clearOptions(){ -// This overloads the action and activate some options +void Action::clearOptions() { +// This overloads the action and activate some options options.clear(); } -void Action::clearDependencies(){ +void Action::clearDependencies() { after.clear(); } -std::string Action::getDocumentation()const{ +std::string Action::getDocumentation()const { return std::string("UNDOCUMENTED ACTION"); } -void Action::checkRead(){ - if(!line.empty()){ +void Action::checkRead() { + if(!line.empty()) { std::string msg="cannot understand the following words from the input line : "; - for(unsigned i=0;i<line.size();i++) msg = msg + line[i] + ", "; + for(unsigned i=0; i<line.size(); i++) msg = msg + line[i] + ", "; error(msg); } } -long int Action::getStep()const{ +long int Action::getStep()const { return plumed.getStep(); } -double Action::getTime()const{ +double Action::getTime()const { return plumed.getAtoms().getTimeStep()*getStep(); } -double Action::getTimeStep()const{ +double Action::getTimeStep()const { return plumed.getAtoms().getTimeStep(); } -void Action::exit(int c){ +void Action::exit(int c) { plumed.exit(c); } -void Action::calculateNumericalDerivatives( ActionWithValue* a ){ +void Action::calculateNumericalDerivatives( ActionWithValue* a ) { plumed_merror("if you get here it means that you are trying to use numerical derivatives for a class that does not implement them"); } -void Action::prepare(){ +void Action::prepare() { return; } @@ -239,32 +239,32 @@ void Action::error( const std::string & msg ) const { plumed_merror("ERROR in input to action " + name + " with label " + label + " : " + msg ); } -void Action::warning( const std::string & msg ){ - log.printf("WARNING for action %s with label %s : %s \n", name.c_str(), label.c_str(), msg.c_str() ); +void Action::warning( const std::string & msg ) { + log.printf("WARNING for action %s with label %s : %s \n", name.c_str(), label.c_str(), msg.c_str() ); } -void Action::calculateFromPDB( const PDB& pdb ){ +void Action::calculateFromPDB( const PDB& pdb ) { activate(); - for(const auto & p : after){ - ActionWithValue*av=dynamic_cast<ActionWithValue*>(p); - if(av){ av->clearInputForces(); av->clearDerivatives(); } - p->readAtomsFromPDB( pdb ); - p->calculate(); + for(const auto & p : after) { + ActionWithValue*av=dynamic_cast<ActionWithValue*>(p); + if(av) { av->clearInputForces(); av->clearDerivatives(); } + p->readAtomsFromPDB( pdb ); + p->calculate(); } readAtomsFromPDB( pdb ); calculate(); } -bool Action::getExchangeStep()const{ +bool Action::getExchangeStep()const { return plumed.getExchangeStep(); } -std::string Action::cite(const std::string&s){ +std::string Action::cite(const std::string&s) { return plumed.cite(s); } /// Check if action should be updated. -bool Action::checkUpdate()const{ +bool Action::checkUpdate()const { double t=getTime(); if(t<update_until && (update_from==std::numeric_limits<double>::max() || t>=update_from)) return true; else return false; diff --git a/src/core/Action.h b/src/core/Action.h index 43cd5d15e..d65208bbc 100644 --- a/src/core/Action.h +++ b/src/core/Action.h @@ -29,16 +29,16 @@ #include "tools/Tools.h" #include "tools/Log.h" -namespace PLMD{ +namespace PLMD { class PDB; class PlumedMain; class Communicator; /// This class is used to bring the relevant information to the Action constructor. -/// Only Action and ActionRegister class can access to its content, which is +/// Only Action and ActionRegister class can access to its content, which is /// kept private to other classes, and may change in the future. -class ActionOptions{ +class ActionOptions { friend class Action; friend class ActionRegister; /// Reference to main PlumedMain object @@ -88,12 +88,12 @@ public: private: /// Actions on which this Action depends. Dependencies after; - + /// Switch to activate Action on this step. bool active; -/// Option that you might have enabled - std::set<std::string> options; +/// Option that you might have enabled + std::set<std::string> options; bool restart; @@ -114,7 +114,7 @@ public: void clearDependencies(); /// Return the present timestep - long int getStep()const; + long int getStep()const; /// Return the present time double getTime()const; @@ -125,7 +125,7 @@ public: /// Return true if we are doing a restart bool getRestart()const; -/// Return true if we are doing at a checkpoint step +/// Return true if we are doing at a checkpoint step bool getCPT()const; /// Just read one of the keywords and return the whole thing as a string @@ -151,8 +151,8 @@ public: void parseFlag(const std::string&key,bool&t); /// Crash calculation and print documentation - void error( const std::string & msg ) const; - + void error( const std::string & msg ) const; + /// Issue a warning void warning( const std::string & msg ); @@ -190,11 +190,11 @@ public: /// By default (if not overridden) does nothing. virtual void prepare(); -/// Register all the relevant keywords for the action +/// Register all the relevant keywords for the action static void registerKeywords( Keywords& keys ); - virtual void lockRequests(){} - virtual void unlockRequests(){} + virtual void lockRequests() {} + virtual void unlockRequests() {} /// Calculate an Action. /// This method is called one or more times per step. @@ -213,17 +213,17 @@ public: /// of the fact that update() is active or not. /// In other words, this is *always* called, even when action /// is not active. - virtual void beforeUpdate(){} + virtual void beforeUpdate() {} /// Update. /// This method is called one time per step. /// The set of all Actions is updated in forward order. - virtual void update(){} + virtual void update() {} /// RunFinalJobs /// This method is called once at the very end of the calculation. /// The set of all Actions in run for the final time in forward order. - virtual void runFinalJobs(){} + virtual void runFinalJobs() {} /// Tell to the Action to flush open files void fflush(); @@ -254,16 +254,16 @@ public: bool isOptionOn(const std::string &s)const; /// Return dependencies - const Dependencies & getDependencies()const{return after;} + const Dependencies & getDependencies()const {return after;} /// Check if numerical derivatives should be performed - virtual bool checkNumericalDerivatives()const{return false;} + virtual bool checkNumericalDerivatives()const {return false;} /// Check if the action needs gradient - virtual bool checkNeedsGradients()const{return false;} + virtual bool checkNeedsGradients()const {return false;} /// Perform calculation using numerical derivatives -/// N.B. only pass an ActionWithValue to this routine if you know exactly what you +/// N.B. only pass an ActionWithValue to this routine if you know exactly what you /// are doing. virtual void calculateNumericalDerivatives( ActionWithValue* a=NULL ); @@ -278,10 +278,10 @@ public: /// Calculate the action given a pdb file as input. This is used to initialize /// things like distance from a point in CV map space given a pdb as an input file void calculateFromPDB( const PDB& ); -/// This is overwritten in ActionAtomistic so that we can read -/// the atoms from the pdb input file rather than taking them from the +/// This is overwritten in ActionAtomistic so that we can read +/// the atoms from the pdb input file rather than taking them from the /// MD code - virtual void readAtomsFromPDB( const PDB& ){} + virtual void readAtomsFromPDB( const PDB& ) {} /// Check if we are on an exchange step bool getExchangeStep()const; @@ -293,17 +293,17 @@ public: // FAST INLINE METHODS inline -const std::string & Action::getLabel()const{ +const std::string & Action::getLabel()const { return label; } inline -const std::string & Action::getName()const{ +const std::string & Action::getName()const { return name; } template<class T> -void Action::parse(const std::string&key,T&t){ +void Action::parse(const std::string&key,T&t) { // if(!Tools::parse(line,key,t)){ // log.printf("ERROR parsing keyword %s\n",key.c_str()); // log.printf("%s\n",getDocumentation().c_str()); @@ -313,26 +313,26 @@ void Action::parse(const std::string&key,T&t){ plumed_massert(keywords.exists(key),"keyword " + key + " has not been registered"); // Now try to read the keyword - std::string def; + std::string def; bool present=Tools::findKeyword(line,key); bool found=Tools::parse(line,key,t,replica_index); if(present && !found) error("keyword " + key +" could not be read correctly"); - - // If it isn't read and it is compulsory see if a default value was specified - if ( !found && (keywords.style(key,"compulsory") || keywords.style(key,"hidden")) ){ - if( keywords.getDefaultValue(key,def) ){ - if( def.length()==0 || !Tools::convert(def,t) ){ - log.printf("ERROR in action %s with label %s : keyword %s has weird default value",name.c_str(),label.c_str(),key.c_str() ); - this->exit(1); - } - } else if( keywords.style(key,"compulsory") ){ - error("keyword " + key + " is compulsory for this action"); - } - } + + // If it isn't read and it is compulsory see if a default value was specified + if ( !found && (keywords.style(key,"compulsory") || keywords.style(key,"hidden")) ) { + if( keywords.getDefaultValue(key,def) ) { + if( def.length()==0 || !Tools::convert(def,t) ) { + log.printf("ERROR in action %s with label %s : keyword %s has weird default value",name.c_str(),label.c_str(),key.c_str() ); + this->exit(1); + } + } else if( keywords.style(key,"compulsory") ) { + error("keyword " + key + " is compulsory for this action"); + } + } } template<class T> -bool Action::parseNumbered(const std::string&key, const int no, T&t){ +bool Action::parseNumbered(const std::string&key, const int no, T&t) { // Check keyword has been registered plumed_massert(keywords.exists(key),"keyword " + key + " has not been registered"); if( !keywords.numbered(key) ) error("numbered keywords are not allowed for " + key ); @@ -343,7 +343,7 @@ bool Action::parseNumbered(const std::string&key, const int no, T&t){ } template<class T> -void Action::parseVector(const std::string&key,std::vector<T>&t){ +void Action::parseVector(const std::string&key,std::vector<T>&t) { // if(!Tools::parseVector(line,key,t)){ // log.printf("ERROR parsing keyword %s\n",key.c_str()); // log.printf("%s\n",getDocumentation().c_str()); @@ -362,31 +362,31 @@ void Action::parseVector(const std::string&key,std::vector<T>&t){ if(present && !found) error("keyword " + key +" could not be read correctly"); // Check vectors size is correct (not if this is atoms or ARG) - if( !keywords.style(key,"atoms") && found ){ + if( !keywords.style(key,"atoms") && found ) { // bool skipcheck=false; // if( keywords.style(key,"compulsory") ){ keywords.getDefaultValue(key,def); skipcheck=(def=="nosize"); } - if( !skipcheck && t.size()!=size ) error("vector read in for keyword " + key + " has the wrong size"); + if( !skipcheck && t.size()!=size ) error("vector read in for keyword " + key + " has the wrong size"); } - // If it isn't read and it is compulsory see if a default value was specified - if ( !found && (keywords.style(key,"compulsory") || keywords.style(key,"hidden")) ){ - if( keywords.getDefaultValue(key,def) ){ - if( def.length()==0 || !Tools::convert(def,val) ){ - log.printf("ERROR in action %s with label %s : keyword %s has weird default value",name.c_str(),label.c_str(),key.c_str() ); - this->exit(1); - } else { - for(unsigned i=0;i<t.size();++i) t[i]=val; - } - } else if( keywords.style(key,"compulsory") ){ - error("keyword " + key + " is compulsory for this action"); - } - } else if ( !found ){ - t.resize(0); - } + // If it isn't read and it is compulsory see if a default value was specified + if ( !found && (keywords.style(key,"compulsory") || keywords.style(key,"hidden")) ) { + if( keywords.getDefaultValue(key,def) ) { + if( def.length()==0 || !Tools::convert(def,val) ) { + log.printf("ERROR in action %s with label %s : keyword %s has weird default value",name.c_str(),label.c_str(),key.c_str() ); + this->exit(1); + } else { + for(unsigned i=0; i<t.size(); ++i) t[i]=val; + } + } else if( keywords.style(key,"compulsory") ) { + error("keyword " + key + " is compulsory for this action"); + } + } else if ( !found ) { + t.resize(0); + } } template<class T> -bool Action::parseNumberedVector(const std::string&key, const int no, std::vector<T>&t){ +bool Action::parseNumberedVector(const std::string&key, const int no, std::vector<T>&t) { plumed_massert(keywords.exists(key),"keyword " + key + " has not been registered"); if( !keywords.numbered(key) ) error("numbered keywords are not allowed for " + key ); @@ -397,37 +397,37 @@ bool Action::parseNumberedVector(const std::string&key, const int no, std::vecto bool found=Tools::parseVector(line,key+num,t,replica_index); if(present && !found) error("keyword " + key +" could not be read correctly"); - if( keywords.style(key,"compulsory") ){ - if (!skipcheck && found && t.size()!=size ) error("vector read in for keyword " + key + num + " has the wrong size"); - } else if ( !found ){ + if( keywords.style(key,"compulsory") ) { + if (!skipcheck && found && t.size()!=size ) error("vector read in for keyword " + key + num + " has the wrong size"); + } else if ( !found ) { t.resize(0); } return found; } inline -void Action::deactivate(){ +void Action::deactivate() { options.clear(); active=false; } inline -bool Action::isActive()const{ +bool Action::isActive()const { return active; } inline -bool Action::isOptionOn(const std::string &s)const{ +bool Action::isOptionOn(const std::string &s)const { return options.count(s); } inline -bool Action::getRestart()const{ +bool Action::getRestart()const { return restart; } inline -bool Action::getCPT()const{ +bool Action::getCPT()const { return doCheckPoint; } diff --git a/src/core/ActionAtomistic.cpp b/src/core/ActionAtomistic.cpp index 288216266..29ed09e3d 100644 --- a/src/core/ActionAtomistic.cpp +++ b/src/core/ActionAtomistic.cpp @@ -37,30 +37,30 @@ using namespace std; namespace PLMD { -ActionAtomistic::~ActionAtomistic(){ +ActionAtomistic::~ActionAtomistic() { // forget the pending request atoms.remove(this); delete(&pbc); } ActionAtomistic::ActionAtomistic(const ActionOptions&ao): -Action(ao), -pbc(*new(Pbc)), -lockRequestAtoms(false), -donotretrieve(false), -donotforce(false), -atoms(plumed.getAtoms()) + Action(ao), + pbc(*new(Pbc)), + lockRequestAtoms(false), + donotretrieve(false), + donotforce(false), + atoms(plumed.getAtoms()) { atoms.add(this); // if(atoms.getNatoms()==0) error("Cannot perform calculations involving atoms without atoms"); } -void ActionAtomistic::registerKeywords( Keywords& keys ){ +void ActionAtomistic::registerKeywords( Keywords& keys ) { (void) keys; // avoid warning } -void ActionAtomistic::requestAtoms(const vector<AtomNumber> & a){ +void ActionAtomistic::requestAtoms(const vector<AtomNumber> & a) { plumed_massert(!lockRequestAtoms,"requested atom list can only be changed in the prepare() method"); int nat=a.size(); indexes=a; @@ -71,7 +71,7 @@ void ActionAtomistic::requestAtoms(const vector<AtomNumber> & a){ int n=atoms.positions.size(); clearDependencies(); unique.clear(); - for(unsigned i=0;i<indexes.size();i++){ + for(unsigned i=0; i<indexes.size(); i++) { if(indexes[i].index()>=n) error("atom out of range"); if(atoms.isVirtualAtom(indexes[i])) addDependency(atoms.getVirtualAtomsAction(indexes[i])); // only real atoms are requested to lower level Atoms class @@ -80,24 +80,24 @@ void ActionAtomistic::requestAtoms(const vector<AtomNumber> & a){ } -Vector ActionAtomistic::pbcDistance(const Vector &v1,const Vector &v2)const{ +Vector ActionAtomistic::pbcDistance(const Vector &v1,const Vector &v2)const { return pbc.distance(v1,v2); } -void ActionAtomistic::pbcApply(std::vector<Vector>& dlist, unsigned max_index)const{ +void ActionAtomistic::pbcApply(std::vector<Vector>& dlist, unsigned max_index)const { pbc.apply(dlist, max_index); } -void ActionAtomistic::calculateNumericalDerivatives( ActionWithValue* a ){ +void ActionAtomistic::calculateNumericalDerivatives( ActionWithValue* a ) { calculateAtomicNumericalDerivatives( a, 0 ); } -void ActionAtomistic::changeBox( const Tensor& newbox ){ +void ActionAtomistic::changeBox( const Tensor& newbox ) { pbc.setBox( newbox ); } -void ActionAtomistic::calculateAtomicNumericalDerivatives( ActionWithValue* a, const unsigned& startnum ){ - if(!a){ +void ActionAtomistic::calculateAtomicNumericalDerivatives( ActionWithValue* a, const unsigned& startnum ) { + if(!a) { a=dynamic_cast<ActionWithValue*>(this); plumed_massert(a,"only Actions with a value can be differentiated"); } @@ -109,109 +109,109 @@ void ActionAtomistic::calculateAtomicNumericalDerivatives( ActionWithValue* a, c std::vector<Vector> savedPositions(natoms); const double delta=sqrt(epsilon); - for(int i=0;i<natoms;i++) for(int k=0;k<3;k++){ - savedPositions[i][k]=positions[i][k]; - positions[i][k]=positions[i][k]+delta; - a->calculate(); - positions[i][k]=savedPositions[i][k]; - for(int j=0;j<nval;j++){ - value[j*natoms+i][k]=a->getOutputQuantity(j); + for(int i=0; i<natoms; i++) for(int k=0; k<3; k++) { + savedPositions[i][k]=positions[i][k]; + positions[i][k]=positions[i][k]+delta; + a->calculate(); + positions[i][k]=savedPositions[i][k]; + for(int j=0; j<nval; j++) { + value[j*natoms+i][k]=a->getOutputQuantity(j); + } + } + Tensor box(pbc.getBox()); + for(int i=0; i<3; i++) for(int k=0; k<3; k++) { + double arg0=box(i,k); + for(int j=0; j<natoms; j++) positions[j]=pbc.realToScaled(positions[j]); + box(i,k)=box(i,k)+delta; + pbc.setBox(box); + for(int j=0; j<natoms; j++) positions[j]=pbc.scaledToReal(positions[j]); + a->calculate(); + box(i,k)=arg0; + pbc.setBox(box); + for(int j=0; j<natoms; j++) positions[j]=savedPositions[j]; + for(int j=0; j<nval; j++) valuebox[j](i,k)=a->getOutputQuantity(j); } - } - Tensor box(pbc.getBox()); - for(int i=0;i<3;i++) for(int k=0;k<3;k++){ - double arg0=box(i,k); - for(int j=0;j<natoms;j++) positions[j]=pbc.realToScaled(positions[j]); - box(i,k)=box(i,k)+delta; - pbc.setBox(box); - for(int j=0;j<natoms;j++) positions[j]=pbc.scaledToReal(positions[j]); - a->calculate(); - box(i,k)=arg0; - pbc.setBox(box); - for(int j=0;j<natoms;j++) positions[j]=savedPositions[j]; - for(int j=0;j<nval;j++) valuebox[j](i,k)=a->getOutputQuantity(j); - } a->calculate(); a->clearDerivatives(); - for(int j=0;j<nval;j++){ + for(int j=0; j<nval; j++) { Value* v=a->copyOutput(j); double ref=v->get(); - if(v->hasDerivatives()){ - for(int i=0;i<natoms;i++) for(int k=0;k<3;k++) { - double d=(value[j*natoms+i][k]-ref)/delta; - v->addDerivative(startnum+3*i+k,d); - } + if(v->hasDerivatives()) { + for(int i=0; i<natoms; i++) for(int k=0; k<3; k++) { + double d=(value[j*natoms+i][k]-ref)/delta; + v->addDerivative(startnum+3*i+k,d); + } Tensor virial; - for(int i=0;i<3;i++) for(int k=0;k<3;k++)virial(i,k)= (valuebox[j](i,k)-ref)/delta; + for(int i=0; i<3; i++) for(int k=0; k<3; k++)virial(i,k)= (valuebox[j](i,k)-ref)/delta; // BE CAREFUL WITH NON ORTHOROMBIC CELL virial=-matmul(box.transpose(),virial); - for(int i=0;i<3;i++) for(int k=0;k<3;k++) v->addDerivative(startnum+3*natoms+3*k+i,virial(k,i)); + for(int i=0; i<3; i++) for(int k=0; k<3; k++) v->addDerivative(startnum+3*natoms+3*k+i,virial(k,i)); } } } -void ActionAtomistic::parseAtomList(const std::string&key, std::vector<AtomNumber> &t){ +void ActionAtomistic::parseAtomList(const std::string&key, std::vector<AtomNumber> &t) { parseAtomList(key,-1,t); } -void ActionAtomistic::parseAtomList(const std::string&key,const int num, std::vector<AtomNumber> &t){ +void ActionAtomistic::parseAtomList(const std::string&key,const int num, std::vector<AtomNumber> &t) { plumed_massert( keywords.style(key,"atoms") || keywords.style(key,"hidden"), "keyword " + key + " should be registered as atoms"); vector<string> strings; - if( num<0 ){ - parseVector(key,strings); - if(strings.empty()) return; + if( num<0 ) { + parseVector(key,strings); + if(strings.empty()) return; } else { - if ( !parseNumberedVector(key,num,strings) ) return; + if ( !parseNumberedVector(key,num,strings) ) return; } interpretAtomList( strings, t ); } -void ActionAtomistic::interpretAtomList( std::vector<std::string>& strings, std::vector<AtomNumber> &t){ +void ActionAtomistic::interpretAtomList( std::vector<std::string>& strings, std::vector<AtomNumber> &t) { Tools::interpretRanges(strings); t.resize(0); - for(unsigned i=0;i<strings.size();++i){ - AtomNumber atom; - bool ok=Tools::convert(strings[i],atom); // this is converting strings to AtomNumbers - if(ok) t.push_back(atom); + for(unsigned i=0; i<strings.size(); ++i) { + AtomNumber atom; + bool ok=Tools::convert(strings[i],atom); // this is converting strings to AtomNumbers + if(ok) t.push_back(atom); // here we check if this is a special symbol for MOLINFO - if( !ok && strings[i].compare(0,1,"@")==0 ){ + if( !ok && strings[i].compare(0,1,"@")==0 ) { std::size_t dot=strings[i].find_first_of("@"); std::string symbol=strings[i].substr(dot+1); vector<SetupMolInfo*> moldat=plumed.getActionSet().select<SetupMolInfo*>(); - if( moldat.size()>0 ){ - vector<AtomNumber> atom_list; moldat[0]->interpretSymbol( symbol, atom_list ); - if( atom_list.size()>0 ){ ok=true; t.insert(t.end(),atom_list.begin(),atom_list.end()); } - else { error(strings[i] + " is not a label plumed knows"); } + if( moldat.size()>0 ) { + vector<AtomNumber> atom_list; moldat[0]->interpretSymbol( symbol, atom_list ); + if( atom_list.size()>0 ) { ok=true; t.insert(t.end(),atom_list.begin(),atom_list.end()); } + else { error(strings[i] + " is not a label plumed knows"); } } else { - error("atoms specified using @ symbol but no MOLINFO was available"); + error("atoms specified using @ symbol but no MOLINFO was available"); } - } + } // here we check if the atom name is the name of a group - if(!ok){ - if(atoms.groups.count(strings[i])){ - const auto m=atoms.groups.find(strings[i]); - t.insert(t.end(),m->second.begin(),m->second.end()); - ok=true; - } - } + if(!ok) { + if(atoms.groups.count(strings[i])) { + const auto m=atoms.groups.find(strings[i]); + t.insert(t.end(),m->second.begin(),m->second.end()); + ok=true; + } + } // here we check if the atom name is the name of an added virtual atom - if(!ok){ - const ActionSet&actionSet(plumed.getActionSet()); - for(const auto & a : actionSet){ - ActionWithVirtualAtom* c=dynamic_cast<ActionWithVirtualAtom*>(a); - if(c) if(c->getLabel()==strings[i]){ - ok=true; - t.push_back(c->getIndex()); - break; - } - } - } - if(!ok) error("it was not possible to interpret atom name " + strings[i]); - // plumed_massert(ok,"it was not possible to interpret atom name " + strings[i]); + if(!ok) { + const ActionSet&actionSet(plumed.getActionSet()); + for(const auto & a : actionSet) { + ActionWithVirtualAtom* c=dynamic_cast<ActionWithVirtualAtom*>(a); + if(c) if(c->getLabel()==strings[i]) { + ok=true; + t.push_back(c->getIndex()); + break; + } + } + } + if(!ok) error("it was not possible to interpret atom name " + strings[i]); + // plumed_massert(ok,"it was not possible to interpret atom name " + strings[i]); } -} +} -void ActionAtomistic::retrieveAtoms(){ +void ActionAtomistic::retrieveAtoms() { pbc=atoms.pbc; Colvar*cc=dynamic_cast<Colvar*>(this); if(cc && cc->checkIsEnergy()) energy=atoms.getEnergy(); @@ -220,15 +220,15 @@ void ActionAtomistic::retrieveAtoms(){ const vector<Vector> & p(atoms.positions); const vector<double> & c(atoms.charges); const vector<double> & m(atoms.masses); - for(unsigned j=0;j<indexes.size();j++) positions[j]=p[indexes[j].index()]; - for(unsigned j=0;j<indexes.size();j++) charges[j]=c[indexes[j].index()]; - for(unsigned j=0;j<indexes.size();j++) masses[j]=m[indexes[j].index()]; + for(unsigned j=0; j<indexes.size(); j++) positions[j]=p[indexes[j].index()]; + for(unsigned j=0; j<indexes.size(); j++) charges[j]=c[indexes[j].index()]; + for(unsigned j=0; j<indexes.size(); j++) masses[j]=m[indexes[j].index()]; } -void ActionAtomistic::setForcesOnAtoms( const std::vector<double>& forcesToApply, unsigned ind ){ +void ActionAtomistic::setForcesOnAtoms( const std::vector<double>& forcesToApply, unsigned ind ) { if(donotforce) return; - for(unsigned i=0;i<indexes.size();++i){ - forces[i][0]=forcesToApply[ind]; ind++; + for(unsigned i=0; i<indexes.size(); ++i) { + forces[i][0]=forcesToApply[ind]; ind++; forces[i][1]=forcesToApply[ind]; ind++; forces[i][2]=forcesToApply[ind]; ind++; } @@ -244,38 +244,38 @@ void ActionAtomistic::setForcesOnAtoms( const std::vector<double>& forcesToApply plumed_dbg_assert( ind+1==forcesToApply.size()); } -void ActionAtomistic::applyForces(){ +void ActionAtomistic::applyForces() { if(donotforce) return; vector<Vector> & f(atoms.forces); Tensor & v(atoms.virial); - for(unsigned j=0;j<indexes.size();j++) f[indexes[j].index()]+=forces[j]; + for(unsigned j=0; j<indexes.size(); j++) f[indexes[j].index()]+=forces[j]; v+=virial; atoms.forceOnEnergy+=forceOnEnergy; } -void ActionAtomistic::clearOutputForces(){ +void ActionAtomistic::clearOutputForces() { virial.zero(); if(donotforce) return; - for(unsigned i=0;i<forces.size();++i)forces[i].zero(); + for(unsigned i=0; i<forces.size(); ++i)forces[i].zero(); forceOnEnergy=0.0; } -void ActionAtomistic::readAtomsFromPDB( const PDB& pdb ){ +void ActionAtomistic::readAtomsFromPDB( const PDB& pdb ) { Colvar*cc=dynamic_cast<Colvar*>(this); if(cc && cc->checkIsEnergy()) error("can't read energies from pdb files"); - for(unsigned j=0;j<indexes.size();j++){ - if( indexes[j].index()>pdb.size() ) error("there are not enough atoms in the input pdb file"); - if( pdb.getAtomNumbers()[j].index()!=indexes[j].index() ) error("there are atoms missing in the pdb file"); - positions[j]=pdb.getPositions()[indexes[j].index()]; + for(unsigned j=0; j<indexes.size(); j++) { + if( indexes[j].index()>pdb.size() ) error("there are not enough atoms in the input pdb file"); + if( pdb.getAtomNumbers()[j].index()!=indexes[j].index() ) error("there are atoms missing in the pdb file"); + positions[j]=pdb.getPositions()[indexes[j].index()]; } - for(unsigned j=0;j<indexes.size();j++) charges[j]=pdb.getBeta()[indexes[j].index()]; - for(unsigned j=0;j<indexes.size();j++) masses[j]=pdb.getOccupancy()[indexes[j].index()]; + for(unsigned j=0; j<indexes.size(); j++) charges[j]=pdb.getBeta()[indexes[j].index()]; + for(unsigned j=0; j<indexes.size(); j++) masses[j]=pdb.getOccupancy()[indexes[j].index()]; } -void ActionAtomistic::makeWhole(){ - for(unsigned j=0;j<positions.size()-1;++j){ +void ActionAtomistic::makeWhole() { + for(unsigned j=0; j<positions.size()-1; ++j) { const Vector & first (positions[j]); Vector & second (positions[j+1]); second=first+pbcDistance(first,second); diff --git a/src/core/ActionAtomistic.h b/src/core/ActionAtomistic.h index 6ea78609c..cec10f268 100644 --- a/src/core/ActionAtomistic.h +++ b/src/core/ActionAtomistic.h @@ -38,7 +38,7 @@ class PDB; /// Action used to create objects that access the positions of the atoms from the MD code class ActionAtomistic : virtual public Action - { +{ std::vector<AtomNumber> indexes; // the set of needed atoms std::set<AtomNumber> unique; @@ -111,7 +111,7 @@ public: /// Get a reference to force on energy double & modifyForceOnEnergy(); /// Get number of available atoms - unsigned getNumberOfAtoms()const{return indexes.size();} + unsigned getNumberOfAtoms()const {return indexes.size();} /// Compute the pbc distance between two positions Vector pbcDistance(const Vector&,const Vector&)const; /// Applies PBCs to a seriens of positions or distances @@ -126,7 +126,7 @@ public: void parseAtomList(const std::string&key,const int num, std::vector<AtomNumber> &t); /// Convert a set of read in strings into an atom list (this is used in parseAtomList) void interpretAtomList( std::vector<std::string>& strings, std::vector<AtomNumber> &t); -/// Change the box shape +/// Change the box shape void changeBox( const Tensor& newbox ); /// Get reference to Pbc const Pbc & getPbc() const; @@ -137,15 +137,15 @@ public: /// not going to be retrieved. Can be used for optimization. Notice that /// calling getPosition(int) in an Action where DoNotRetrieve() was called might /// lead to undefined behavior. - void doNotRetrieve(){donotretrieve=true;} + void doNotRetrieve() {donotretrieve=true;} /// Skip atom forces - use with care. /// If this function is called during initialization, then forces are /// not going to be propagated. Can be used for optimization. - void doNotForce(){donotforce=true;} + void doNotForce() {donotforce=true;} /// Make atoms whole, assuming they are in the proper order void makeWhole(); /// Allow calls to modifyGlobalForce() - void allowToAccessGlobalForces(){atoms.zeroallforces=true;} + void allowToAccessGlobalForces() {atoms.zeroallforces=true;} public: // virtual functions: @@ -157,10 +157,10 @@ public: void clearOutputForces(); -/// N.B. only pass an ActionWithValue to this routine if you know exactly what you +/// N.B. only pass an ActionWithValue to this routine if you know exactly what you /// are doing. The default will be correct for the vast majority of cases virtual void calculateNumericalDerivatives( ActionWithValue* a=NULL ); -/// Numerical derivative routine to use when using Actions that inherit from BOTH +/// Numerical derivative routine to use when using Actions that inherit from BOTH /// ActionWithArguments and ActionAtomistic void calculateAtomicNumericalDerivatives( ActionWithValue* a, const unsigned& startnum ); @@ -169,38 +169,38 @@ public: void lockRequests(); void unlockRequests(); const std::set<AtomNumber> & getUnique()const; -/// Read in an input file containing atom positions and calculate the action for the atomic +/// Read in an input file containing atom positions and calculate the action for the atomic /// configuration therin void readAtomsFromPDB( const PDB& pdb ); }; inline -const Vector & ActionAtomistic::getPosition(int i)const{ +const Vector & ActionAtomistic::getPosition(int i)const { return positions[i]; } inline -const Vector & ActionAtomistic::getPosition(AtomNumber i)const{ +const Vector & ActionAtomistic::getPosition(AtomNumber i)const { return atoms.positions[i.index()]; } inline -Vector & ActionAtomistic::modifyPosition(AtomNumber i){ +Vector & ActionAtomistic::modifyPosition(AtomNumber i) { return atoms.positions[i.index()]; } inline -Vector & ActionAtomistic::modifyGlobalForce(AtomNumber i){ +Vector & ActionAtomistic::modifyGlobalForce(AtomNumber i) { return atoms.forces[i.index()]; } inline -Tensor & ActionAtomistic::modifyGlobalVirial(){ +Tensor & ActionAtomistic::modifyGlobalVirial() { return atoms.virial; } inline -double ActionAtomistic::getMass(int i)const{ +double ActionAtomistic::getMass(int i)const { return masses[i]; } @@ -211,72 +211,72 @@ double ActionAtomistic::getCharge(int i) const { } inline -const std::vector<AtomNumber> & ActionAtomistic::getAbsoluteIndexes()const{ +const std::vector<AtomNumber> & ActionAtomistic::getAbsoluteIndexes()const { return indexes; } inline -AtomNumber ActionAtomistic::getAbsoluteIndex(int i)const{ +AtomNumber ActionAtomistic::getAbsoluteIndex(int i)const { return indexes[i]; } inline -const std::vector<Vector> & ActionAtomistic::getPositions()const{ +const std::vector<Vector> & ActionAtomistic::getPositions()const { return positions; } inline -const double & ActionAtomistic::getEnergy()const{ +const double & ActionAtomistic::getEnergy()const { return energy; } inline -const Tensor & ActionAtomistic::getBox()const{ +const Tensor & ActionAtomistic::getBox()const { return pbc.getBox(); } inline -std::vector<Vector> & ActionAtomistic::modifyForces(){ +std::vector<Vector> & ActionAtomistic::modifyForces() { return forces; } inline -Tensor & ActionAtomistic::modifyVirial(){ +Tensor & ActionAtomistic::modifyVirial() { return virial; } inline -double & ActionAtomistic::modifyForceOnEnergy(){ +double & ActionAtomistic::modifyForceOnEnergy() { return forceOnEnergy; } inline -const Pbc & ActionAtomistic::getPbc() const{ - return pbc; +const Pbc & ActionAtomistic::getPbc() const { + return pbc; } inline -void ActionAtomistic::lockRequests(){ +void ActionAtomistic::lockRequests() { lockRequestAtoms=true; } inline -void ActionAtomistic::unlockRequests(){ +void ActionAtomistic::unlockRequests() { lockRequestAtoms=false; } inline -const std::set<AtomNumber> & ActionAtomistic::getUnique()const{ +const std::set<AtomNumber> & ActionAtomistic::getUnique()const { return unique; } inline -unsigned ActionAtomistic::getTotAtoms()const{ +unsigned ActionAtomistic::getTotAtoms()const { return atoms.positions.size(); } inline -Pbc & ActionAtomistic::modifyGlobalPbc(){ +Pbc & ActionAtomistic::modifyGlobalPbc() { return atoms.pbc; } diff --git a/src/core/ActionPilot.cpp b/src/core/ActionPilot.cpp index 10007dedc..fbd6d3bb2 100644 --- a/src/core/ActionPilot.cpp +++ b/src/core/ActionPilot.cpp @@ -22,33 +22,33 @@ #include "ActionPilot.h" using namespace std; -namespace PLMD{ +namespace PLMD { -void ActionPilot::registerKeywords(Keywords& keys){ +void ActionPilot::registerKeywords(Keywords& keys) { } ActionPilot::ActionPilot(const ActionOptions&ao): -Action(ao), -stride(1) + Action(ao), + stride(1) { - if( keywords.exists("STRIDE") ){ - parse("STRIDE",stride); - if( !keywords.style("STRIDE","hidden") ) log.printf(" with stride %d\n",stride); + if( keywords.exists("STRIDE") ) { + parse("STRIDE",stride); + if( !keywords.style("STRIDE","hidden") ) log.printf(" with stride %d\n",stride); } else { - stride=0; + stride=0; } } -bool ActionPilot::onStep()const{ +bool ActionPilot::onStep()const { if( stride>0 ) return getStep()%stride==0; return false; } -int ActionPilot::getStride()const{ +int ActionPilot::getStride()const { return stride; } -void ActionPilot::setStride( const int& n ){ +void ActionPilot::setStride( const int& n ) { stride=n; } diff --git a/src/core/ActionPilot.h b/src/core/ActionPilot.h index 007508ca6..bf3e02446 100644 --- a/src/core/ActionPilot.h +++ b/src/core/ActionPilot.h @@ -24,13 +24,13 @@ #include "Action.h" -namespace PLMD{ +namespace PLMD { /** \ingroup MULTIINHERIT This is used to create PLMD::Action objects that are run with some set frequency. -Any PLMD::Action -that does not inherit from PLMD::Action is only run when some other Action requires the output from +Any PLMD::Action +that does not inherit from PLMD::Action is only run when some other Action requires the output from it in order to run. This class is used in PLMD::Bias Action which drives the execution of other Action's. Action's of this kind are executed with a fixed stride diff --git a/src/core/ActionRegister.cpp b/src/core/ActionRegister.cpp index b948e69a5..e064392c3 100644 --- a/src/core/ActionRegister.cpp +++ b/src/core/ActionRegister.cpp @@ -27,34 +27,34 @@ using namespace std; -namespace PLMD{ +namespace PLMD { -ActionRegister::~ActionRegister(){ - if(m.size()>0){ +ActionRegister::~ActionRegister() { + if(m.size()>0) { string names=""; for(const auto & p : m) names+=p.first+" "; std::cerr<<"WARNING: Directive "+ names +" has not been properly unregistered. This might lead to memory leak!!\n"; } } -ActionRegister& actionRegister(){ +ActionRegister& actionRegister() { static ActionRegister ans; return ans; } -void ActionRegister::remove(creator_pointer f){ - for(auto p=m.begin();p!=m.end();++p){ - if((*p).second==f){ +void ActionRegister::remove(creator_pointer f) { + for(auto p=m.begin(); p!=m.end(); ++p) { + if((*p).second==f) { m.erase(p); break; } } } -void ActionRegister::add(string key,creator_pointer f,keywords_pointer k){ - if(m.count(key)){ +void ActionRegister::add(string key,creator_pointer f,keywords_pointer k) { + if(m.count(key)) { m.erase(key); disabled.insert(key); - }else{ + } else { m.insert(pair<string,creator_pointer>(key,f)); // Store a pointer to the function that creates keywords // A pointer is stored and not the keywords because all @@ -63,66 +63,66 @@ void ActionRegister::add(string key,creator_pointer f,keywords_pointer k){ }; } -bool ActionRegister::check(string key){ +bool ActionRegister::check(string key) { if(m.count(key)>0 && mk.count(key)>0) return true; return false; } -Action* ActionRegister::create(const ActionOptions&ao){ +Action* ActionRegister::create(const ActionOptions&ao) { if(ao.line.size()<1)return NULL; - // Create a copy of the manual locally. The manual is - // then added to the ActionOptions. This allows us to + // Create a copy of the manual locally. The manual is + // then added to the ActionOptions. This allows us to // ensure during construction that all the keywords for // the action have been documented. In addition, we can // generate the documentation when the user makes an error // in the input. Action* action; - if( check(ao.line[0]) ){ - Keywords keys; mk[ao.line[0]](keys); - ActionOptions nao( ao,keys ); - action=m[ao.line[0]](nao); - keys.destroyData(); + if( check(ao.line[0]) ) { + Keywords keys; mk[ao.line[0]](keys); + ActionOptions nao( ao,keys ); + action=m[ao.line[0]](nao); + keys.destroyData(); } else action=NULL; return action; } -bool ActionRegister::printManual( const std::string& action, const bool& vimout ){ - if ( check(action) ){ - Keywords keys; mk[action](keys); - if( vimout ){ - printf("%s",action.c_str()); keys.print_vim(); printf("\n"); - } else { - keys.print_html(); - } - keys.destroyData(); - return true; +bool ActionRegister::printManual( const std::string& action, const bool& vimout ) { + if ( check(action) ) { + Keywords keys; mk[action](keys); + if( vimout ) { + printf("%s",action.c_str()); keys.print_vim(); printf("\n"); + } else { + keys.print_html(); + } + keys.destroyData(); + return true; } else { - return false; - } + return false; + } } -bool ActionRegister::printTemplate( const std::string& action, bool include_optional ){ - if( check(action) ){ - Keywords keys; mk[action](keys); - keys.print_template(action, include_optional); keys.destroyData(); - return true; +bool ActionRegister::printTemplate( const std::string& action, bool include_optional ) { + if( check(action) ) { + Keywords keys; mk[action](keys); + keys.print_template(action, include_optional); keys.destroyData(); + return true; } else { - return false; + return false; } } -std::ostream & operator<<(std::ostream &log,const ActionRegister&ar){ +std::ostream & operator<<(std::ostream &log,const ActionRegister&ar) { vector<string> s; for(const auto & it : ar.m) s.push_back(it.first); sort(s.begin(),s.end()); - for(unsigned i=0;i<s.size();i++) log<<" "<<s[i]<<"\n"; - if(!ar.disabled.empty()){ + for(unsigned i=0; i<s.size(); i++) log<<" "<<s[i]<<"\n"; + if(!ar.disabled.empty()) { s.assign(ar.disabled.size(),""); copy(ar.disabled.begin(),ar.disabled.end(),s.begin()); sort(s.begin(),s.end()); log<<"+++++++ WARNING +++++++\n"; log<<"The following keywords have been registered more than once and will be disabled:\n"; - for(unsigned i=0;i<s.size();i++) log<<" - "<<s[i]<<"\n"; + for(unsigned i=0; i<s.size(); i++) log<<" - "<<s[i]<<"\n"; log<<"+++++++ END WARNING +++++++\n"; }; return log; diff --git a/src/core/ActionRegister.h b/src/core/ActionRegister.h index a672b361f..5d02a1d1b 100644 --- a/src/core/ActionRegister.h +++ b/src/core/ActionRegister.h @@ -28,7 +28,7 @@ #include <iosfwd> #include "tools/Keywords.h" -namespace PLMD{ +namespace PLMD { class Action; class ActionOptions; @@ -42,7 +42,7 @@ class ActionOptions; /// If the same directive is used for different classes, it is automatically disabled /// to avoid random results. /// -class ActionRegister{ +class ActionRegister { /// Write on a stream the list of registered directives friend std::ostream &operator<<(std::ostream &,const ActionRegister&); /// Pointer to a function which, given the options, create an Action @@ -67,8 +67,8 @@ public: /// \param ao object containing information for initialization, such as the full input line, a pointer to PlumedMain, etc Action* create(const ActionOptions&ao); /// Print out the keywords for an action in html/vim ready for input into the manual - bool printManual(const std::string& action, const bool& vimout); -/// Print out a template command for an action + bool printManual(const std::string& action, const bool& vimout); +/// Print out a template command for an action bool printTemplate(const std::string& action, bool include_optional); void remove(creator_pointer); ~ActionRegister(); diff --git a/src/core/ActionSet.cpp b/src/core/ActionSet.cpp index 9a1735dc2..35334eca2 100644 --- a/src/core/ActionSet.cpp +++ b/src/core/ActionSet.cpp @@ -22,35 +22,35 @@ #include "ActionSet.h" using namespace std; -namespace PLMD{ +namespace PLMD { ActionSet::ActionSet(PlumedMain&p): -plumed(p){ + plumed(p) { (void) plumed; // to suppress warning about "unused plumed" } ActionSet::~ActionSet() { - for(int i=size()-1;i>=0;i--) delete (*this)[i]; + for(int i=size()-1; i>=0; i--) delete (*this)[i]; } -void ActionSet::clearDelete(){ - for(int i=size()-1;i>=0;i--) delete (*this)[i]; +void ActionSet::clearDelete() { + for(int i=size()-1; i>=0; i--) delete (*this)[i]; clear(); } -std::string ActionSet::getLabelList() const{ +std::string ActionSet::getLabelList() const { std::string outlist; - for(const auto & p : (*this)){ + for(const auto & p : (*this)) { outlist+=dynamic_cast<Action*>(p)->getLabel()+" "; }; return outlist; } -std::vector<std::string> ActionSet::getLabelVector() const{ +std::vector<std::string> ActionSet::getLabelVector() const { std::vector<std::string> outlist; - for(const auto & p : (*this)){ + for(const auto & p : (*this)) { outlist.push_back(dynamic_cast<Action*>(p)->getLabel()); }; return outlist; diff --git a/src/core/ActionSet.h b/src/core/ActionSet.h index 17b605dbf..c2d48a269 100644 --- a/src/core/ActionSet.h +++ b/src/core/ActionSet.h @@ -62,7 +62,7 @@ public: T selectWithLabel(const std::string&s)const; /// get the labels in the list of actions in form of a string (useful to debug) std::string getLabelList() const; -/// get the labels in the form of a vector of strings +/// get the labels in the form of a vector of strings std::vector<std::string> getLabelVector() const; }; @@ -70,9 +70,9 @@ public: // INLINE IMPLEMENTATIONS: template <class T> -std::vector<T> ActionSet::select()const{ +std::vector<T> ActionSet::select()const { std::vector<T> ret; - for(const auto & p : (*this)){ + for(const auto & p : (*this)) { T t=dynamic_cast<T>(p); if(t) ret.push_back(t); }; @@ -80,8 +80,8 @@ std::vector<T> ActionSet::select()const{ } template <class T> -T ActionSet::selectWithLabel(const std::string&s)const{ - for(const auto & p : (*this)){ +T ActionSet::selectWithLabel(const std::string&s)const { + for(const auto & p : (*this)) { T t=dynamic_cast<T>(p); if(t && dynamic_cast<Action*>(t)->getLabel()==s) return t; }; @@ -89,9 +89,9 @@ T ActionSet::selectWithLabel(const std::string&s)const{ } template <class T> -std::vector<Action*> ActionSet::selectNot()const{ +std::vector<Action*> ActionSet::selectNot()const { std::vector<Action*> ret; - for(const auto & p : (*this)){ + for(const auto & p : (*this)) { T t=dynamic_cast<T>(p); if(!t) ret.push_back(p); }; diff --git a/src/core/ActionSetup.cpp b/src/core/ActionSetup.cpp index 9bc9e527b..1a0216a7b 100644 --- a/src/core/ActionSetup.cpp +++ b/src/core/ActionSetup.cpp @@ -24,19 +24,19 @@ #include "ActionSet.h" #include "tools/Exception.h" -namespace PLMD{ +namespace PLMD { ActionSetup::ActionSetup(const ActionOptions&ao): Action(ao) { const ActionSet& actionset(plumed.getActionSet()); - for(const auto & p : actionset){ + for(const auto & p : actionset) { // check that all the preceeding actions are ActionSetup if( !dynamic_cast<ActionSetup*>(p) ) error("Action " + getLabel() + " is a setup action, and should be only preceeded by other setup actions"); } } -void ActionSetup::registerKeywords( Keywords& keys ){ +void ActionSetup::registerKeywords( Keywords& keys ) { Action::registerKeywords(keys); keys.remove("LABEL"); } diff --git a/src/core/ActionSetup.h b/src/core/ActionSetup.h index bb9dfc5dc..d76a0bea1 100644 --- a/src/core/ActionSetup.h +++ b/src/core/ActionSetup.h @@ -24,7 +24,7 @@ #include "Action.h" -namespace PLMD{ +namespace PLMD { /** \ingroup MULTIINHERIT @@ -36,11 +36,11 @@ public: /// Constructor explicit ActionSetup(const ActionOptions&ao); /// Creator of keywords - static void registerKeywords( Keywords& keys ); + static void registerKeywords( Keywords& keys ); /// Do nothing. - void calculate(){} + void calculate() {} /// Do nothing. - void apply(){} + void apply() {} }; } diff --git a/src/core/ActionWithArguments.cpp b/src/core/ActionWithArguments.cpp index b492410ca..23b772938 100644 --- a/src/core/ActionWithArguments.cpp +++ b/src/core/ActionWithArguments.cpp @@ -25,217 +25,217 @@ #include "PlumedMain.h" #include "ActionSet.h" #include <iostream> -#ifdef __PLUMED_HAS_CREGEX +#ifdef __PLUMED_HAS_CREGEX #include <cstring> -#include "regex.h" +#include "regex.h" #endif using namespace std; -namespace PLMD{ +namespace PLMD { -void ActionWithArguments::registerKeywords(Keywords& keys){ +void ActionWithArguments::registerKeywords(Keywords& keys) { keys.reserve("numbered","ARG","the input for this action is the scalar output from one or more other actions. The particular scalars that you will use " - "are referenced using the label of the action. If the label appears on its own then it is assumed that the Action calculates " - "a single scalar value. The value of this scalar is thus used as the input to this new action. If * or *.* appears the " - "scalars calculated by all the proceding actions in the input file are taken. Some actions have multi-component outputs and " - "each component of the output has a specific label. For example a \\ref DISTANCE action labelled dist may have three componets " - "x, y and z. To take just the x component you should use dist.x, if you wish to take all three components then use dist.*." - "More information on the referencing of Actions can be found in the section of the manual on the PLUMED \\ref Syntax. " - "Scalar values can also be " - "referenced using POSIX regular expressions as detailed in the section on \\ref Regex. To use this feature you you must compile " - "PLUMED with the appropriate flag."); + "are referenced using the label of the action. If the label appears on its own then it is assumed that the Action calculates " + "a single scalar value. The value of this scalar is thus used as the input to this new action. If * or *.* appears the " + "scalars calculated by all the proceding actions in the input file are taken. Some actions have multi-component outputs and " + "each component of the output has a specific label. For example a \\ref DISTANCE action labelled dist may have three componets " + "x, y and z. To take just the x component you should use dist.x, if you wish to take all three components then use dist.*." + "More information on the referencing of Actions can be found in the section of the manual on the PLUMED \\ref Syntax. " + "Scalar values can also be " + "referenced using POSIX regular expressions as detailed in the section on \\ref Regex. To use this feature you you must compile " + "PLUMED with the appropriate flag."); } -void ActionWithArguments::parseArgumentList(const std::string&key,std::vector<Value*>&arg){ - vector<string> c; arg.clear(); parseVector(key,c); - if( c.size()==0 && (keywords.style(key,"compulsory") || keywords.style(key,"hidden")) ){ +void ActionWithArguments::parseArgumentList(const std::string&key,std::vector<Value*>&arg) { + vector<string> c; arg.clear(); parseVector(key,c); + if( c.size()==0 && (keywords.style(key,"compulsory") || keywords.style(key,"hidden")) ) { std::string def; if( keywords.getDefaultValue(key,def) ) c.push_back( def ); } interpretArgumentList(c,arg); } -bool ActionWithArguments::parseArgumentList(const std::string&key,int i,std::vector<Value*>&arg){ - vector<string> c; - arg.clear(); +bool ActionWithArguments::parseArgumentList(const std::string&key,int i,std::vector<Value*>&arg) { + vector<string> c; + arg.clear(); if(parseNumberedVector(key,i,c)) { interpretArgumentList(c,arg); return true; } else return false; } -void ActionWithArguments::interpretArgumentList(const std::vector<std::string>& c, std::vector<Value*>&arg){ - for(unsigned i=0;i<c.size();i++){ - // is a regex? then just interpret it. The signal is () - std::size_t found1 = c[i].find("("); - if(found1!=std::string::npos){ - std::size_t found2=c[i].find(")",found1+1,1); // find it again - if(found2!=std::string::npos){ - // start regex parsing -#ifdef __PLUMED_HAS_CREGEX - // take the string enclosed in quotes and put in round brackets - std::string myregex=c[i].substr(found1,found2-found1+1); - log.printf(" Evaluating regexp for this action: %s \n",myregex.c_str()); - int errcode; - regex_t *preg = (regex_t*)malloc(sizeof(regex_t)); // pointer to the regular expression - regmatch_t *pmatch; - if ((errcode=regcomp(preg, myregex.c_str() ,REG_EXTENDED|REG_NEWLINE))) { // compile the regular expression - char* errbuf; - size_t errbuf_size; - // one can check the errors asking to regerror - errbuf_size = regerror(errcode, preg, NULL, 0); - if (!(errbuf=(char*)malloc(errbuf_size))) { - plumed_merror("cannot allocate the buffer for error detection in regexp!"); - }; - regerror(errcode, preg, errbuf, errbuf_size); - error(errbuf); - } - plumed_massert(preg->re_nsub==1,"I can parse with only one subexpression"); - pmatch = (regmatch_t*)malloc(sizeof(regmatch_t)*preg->re_nsub); - // select all the actions that have a value - std::vector<ActionWithValue*> all=plumed.getActionSet().select<ActionWithValue*>(); - if( all.empty() ) error("your input file is not telling plumed to calculate anything"); - for(unsigned j=0;j<all.size();j++){ - std::vector<std::string> ss=all[j]->getComponentsVector(); - for(unsigned k=0;k<ss.size();++k){ - unsigned ll=strlen(ss[k].c_str())+1; - std::vector<char> str(ll); - strcpy(&str[0],ss[k].c_str()); - const char *ppstr=&str[0]; - if(!regexec(preg, ppstr , preg->re_nsub, pmatch, 0)) { - log.printf(" Something matched with \"%s\" : ",ss[k].c_str()); - do { - if (pmatch[0].rm_so != -1) { /* The regex is matching part of a string */ - char *submatch; - size_t matchlen = pmatch[0].rm_eo - pmatch[0].rm_so; - submatch = (char*)malloc(matchlen+1); - strncpy(submatch, ppstr+pmatch[0].rm_so, matchlen+1); - submatch[matchlen]='\0'; - log.printf(" subpattern %s\n", submatch); - // this is the match: try to see if it is a valid action - std::string putativeVal(submatch); - if( all[j]->exists(putativeVal) ){ - arg.push_back(all[j]->copyOutput(putativeVal)); - log.printf(" Action %s added! \n",putativeVal.c_str()); - } - free(submatch); - }; - ppstr += pmatch[0].rm_eo; /* Restart from last match */ - } while(!regexec(preg,ppstr,preg->re_nsub,pmatch,0)); - } - } - }; - regfree(preg); - free(preg); - free(pmatch); +void ActionWithArguments::interpretArgumentList(const std::vector<std::string>& c, std::vector<Value*>&arg) { + for(unsigned i=0; i<c.size(); i++) { + // is a regex? then just interpret it. The signal is () + std::size_t found1 = c[i].find("("); + if(found1!=std::string::npos) { + std::size_t found2=c[i].find(")",found1+1,1); // find it again + if(found2!=std::string::npos) { + // start regex parsing +#ifdef __PLUMED_HAS_CREGEX + // take the string enclosed in quotes and put in round brackets + std::string myregex=c[i].substr(found1,found2-found1+1); + log.printf(" Evaluating regexp for this action: %s \n",myregex.c_str()); + int errcode; + regex_t *preg = (regex_t*)malloc(sizeof(regex_t)); // pointer to the regular expression + regmatch_t *pmatch; + if ((errcode=regcomp(preg, myregex.c_str(),REG_EXTENDED|REG_NEWLINE))) { // compile the regular expression + char* errbuf; + size_t errbuf_size; + // one can check the errors asking to regerror + errbuf_size = regerror(errcode, preg, NULL, 0); + if (!(errbuf=(char*)malloc(errbuf_size))) { + plumed_merror("cannot allocate the buffer for error detection in regexp!"); + }; + regerror(errcode, preg, errbuf, errbuf_size); + error(errbuf); + } + plumed_massert(preg->re_nsub==1,"I can parse with only one subexpression"); + pmatch = (regmatch_t*)malloc(sizeof(regmatch_t)*preg->re_nsub); + // select all the actions that have a value + std::vector<ActionWithValue*> all=plumed.getActionSet().select<ActionWithValue*>(); + if( all.empty() ) error("your input file is not telling plumed to calculate anything"); + for(unsigned j=0; j<all.size(); j++) { + std::vector<std::string> ss=all[j]->getComponentsVector(); + for(unsigned k=0; k<ss.size(); ++k) { + unsigned ll=strlen(ss[k].c_str())+1; + std::vector<char> str(ll); + strcpy(&str[0],ss[k].c_str()); + const char *ppstr=&str[0]; + if(!regexec(preg, ppstr, preg->re_nsub, pmatch, 0)) { + log.printf(" Something matched with \"%s\" : ",ss[k].c_str()); + do { + if (pmatch[0].rm_so != -1) { /* The regex is matching part of a string */ + char *submatch; + size_t matchlen = pmatch[0].rm_eo - pmatch[0].rm_so; + submatch = (char*)malloc(matchlen+1); + strncpy(submatch, ppstr+pmatch[0].rm_so, matchlen+1); + submatch[matchlen]='\0'; + log.printf(" subpattern %s\n", submatch); + // this is the match: try to see if it is a valid action + std::string putativeVal(submatch); + if( all[j]->exists(putativeVal) ) { + arg.push_back(all[j]->copyOutput(putativeVal)); + log.printf(" Action %s added! \n",putativeVal.c_str()); + } + free(submatch); + }; + ppstr += pmatch[0].rm_eo; /* Restart from last match */ + } while(!regexec(preg,ppstr,preg->re_nsub,pmatch,0)); + } + } + }; + regfree(preg); + free(preg); + free(pmatch); #else - plumed_merror("Regexp support not compiled!"); + plumed_merror("Regexp support not compiled!"); #endif - }else{ - plumed_merror("did you want to use regexp to input arguments? enclose it between two round braces (...) with no spaces!"); - } - }else{ - std::size_t dot=c[i].find_first_of('.'); - string a=c[i].substr(0,dot); - string name=c[i].substr(dot+1); - if(c[i].find(".")!=string::npos){ // if it contains a dot: - if(a=="*" && name=="*"){ - // Take all values from all actions - std::vector<ActionWithValue*> all=plumed.getActionSet().select<ActionWithValue*>(); - if( all.empty() ) error("your input file is not telling plumed to calculate anything"); - for(unsigned j=0;j<all.size();j++){ - for(int k=0;k<all[j]->getNumberOfComponents();++k) arg.push_back(all[j]->copyOutput(k)); - } - } else if ( name=="*"){ - // Take all the values from an action with a specific name - ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>(a); - if(!action){ - std::string str=" (hint! the actions in this ActionSet are: "; - str+=plumed.getActionSet().getLabelList()+")"; - error("cannot find action named " + a + str); - } - if( action->getNumberOfComponents()==0 ) error("found " + a +".* indicating use all components calculated by action with label " + a + " but this action has no components"); - for(int k=0;k<action->getNumberOfComponents();++k) arg.push_back(action->copyOutput(k)); - } else if ( a=="*" ){ - // Take components from all actions with a specific name - std::vector<ActionWithValue*> all=plumed.getActionSet().select<ActionWithValue*>(); - if( all.empty() ) error("your input file is not telling plumed to calculate anything"); - unsigned nval=0; - for(unsigned j=0;j<all.size();j++){ - std::string flab; flab=all[j]->getLabel() + "." + name; - if( all[j]->exists(flab) ){ arg.push_back(all[j]->copyOutput(flab)); nval++; } - } - if(nval==0) error("found no actions with a component called " + name ); - } else { - // Take values with a specific name - ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>(a); - if(!action){ - std::string str=" (hint! the actions in this ActionSet are: "; - str+=plumed.getActionSet().getLabelList()+")"; - error("cannot find action named " + a +str); - } - if( !(action->exists(c[i])) ){ - std::string str=" (hint! the components in this actions are: "; - str+=action->getComponentsList()+")"; - error("action " + a + " has no component named " + name + str); - } ; - arg.push_back(action->copyOutput(c[i])); - } - } else { // if it doesn't contain a dot - if(c[i]=="*"){ - // Take all values from all actions - std::vector<ActionWithValue*> all=plumed.getActionSet().select<ActionWithValue*>(); - if( all.empty() ) error("your input file is not telling plumed to calculate anything"); - for(unsigned j=0;j<all.size();j++){ - for(int k=0;k<all[j]->getNumberOfComponents();++k) arg.push_back(all[j]->copyOutput(k)); - } - } else { - ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>(c[i]); - if(!action){ - std::string str=" (hint! the actions in this ActionSet are: "; - str+=plumed.getActionSet().getLabelList()+")"; - error("cannot find action named " + c[i] + str ); - } - if( !(action->exists(c[i])) ){ - std::string str=" (hint! the components in this actions are: "; - str+=action->getComponentsList()+")"; - error("action " + c[i] + " has no component named " + c[i] +str); - }; - arg.push_back(action->copyOutput(c[i])); - } - } - } + } else { + plumed_merror("did you want to use regexp to input arguments? enclose it between two round braces (...) with no spaces!"); + } + } else { + std::size_t dot=c[i].find_first_of('.'); + string a=c[i].substr(0,dot); + string name=c[i].substr(dot+1); + if(c[i].find(".")!=string::npos) { // if it contains a dot: + if(a=="*" && name=="*") { + // Take all values from all actions + std::vector<ActionWithValue*> all=plumed.getActionSet().select<ActionWithValue*>(); + if( all.empty() ) error("your input file is not telling plumed to calculate anything"); + for(unsigned j=0; j<all.size(); j++) { + for(int k=0; k<all[j]->getNumberOfComponents(); ++k) arg.push_back(all[j]->copyOutput(k)); + } + } else if ( name=="*") { + // Take all the values from an action with a specific name + ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>(a); + if(!action) { + std::string str=" (hint! the actions in this ActionSet are: "; + str+=plumed.getActionSet().getLabelList()+")"; + error("cannot find action named " + a + str); + } + if( action->getNumberOfComponents()==0 ) error("found " + a +".* indicating use all components calculated by action with label " + a + " but this action has no components"); + for(int k=0; k<action->getNumberOfComponents(); ++k) arg.push_back(action->copyOutput(k)); + } else if ( a=="*" ) { + // Take components from all actions with a specific name + std::vector<ActionWithValue*> all=plumed.getActionSet().select<ActionWithValue*>(); + if( all.empty() ) error("your input file is not telling plumed to calculate anything"); + unsigned nval=0; + for(unsigned j=0; j<all.size(); j++) { + std::string flab; flab=all[j]->getLabel() + "." + name; + if( all[j]->exists(flab) ) { arg.push_back(all[j]->copyOutput(flab)); nval++; } + } + if(nval==0) error("found no actions with a component called " + name ); + } else { + // Take values with a specific name + ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>(a); + if(!action) { + std::string str=" (hint! the actions in this ActionSet are: "; + str+=plumed.getActionSet().getLabelList()+")"; + error("cannot find action named " + a +str); + } + if( !(action->exists(c[i])) ) { + std::string str=" (hint! the components in this actions are: "; + str+=action->getComponentsList()+")"; + error("action " + a + " has no component named " + name + str); + } ; + arg.push_back(action->copyOutput(c[i])); + } + } else { // if it doesn't contain a dot + if(c[i]=="*") { + // Take all values from all actions + std::vector<ActionWithValue*> all=plumed.getActionSet().select<ActionWithValue*>(); + if( all.empty() ) error("your input file is not telling plumed to calculate anything"); + for(unsigned j=0; j<all.size(); j++) { + for(int k=0; k<all[j]->getNumberOfComponents(); ++k) arg.push_back(all[j]->copyOutput(k)); + } + } else { + ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>(c[i]); + if(!action) { + std::string str=" (hint! the actions in this ActionSet are: "; + str+=plumed.getActionSet().getLabelList()+")"; + error("cannot find action named " + c[i] + str ); + } + if( !(action->exists(c[i])) ) { + std::string str=" (hint! the components in this actions are: "; + str+=action->getComponentsList()+")"; + error("action " + c[i] + " has no component named " + c[i] +str); + }; + arg.push_back(action->copyOutput(c[i])); + } + } + } } } -void ActionWithArguments::expandArgKeywordInPDB( PDB& pdb ){ +void ActionWithArguments::expandArgKeywordInPDB( PDB& pdb ) { std::vector<std::string> pdb_remark=pdb.getRemark(); std::vector<std::string> arg_names; bool found=Tools::parseVector(pdb_remark,"ARG",arg_names); - if( found ){ - std::vector<Value*> arg_vals; - interpretArgumentList( arg_names, arg_vals ); - std::string new_args="ARG=" + arg_vals[0]->getName(); - for(unsigned i=1;i<arg_vals.size();++i) new_args = new_args + "," + arg_vals[i]->getName(); - pdb.setArgKeyword( new_args ); + if( found ) { + std::vector<Value*> arg_vals; + interpretArgumentList( arg_names, arg_vals ); + std::string new_args="ARG=" + arg_vals[0]->getName(); + for(unsigned i=1; i<arg_vals.size(); ++i) new_args = new_args + "," + arg_vals[i]->getName(); + pdb.setArgKeyword( new_args ); } } -void ActionWithArguments::requestArguments(const vector<Value*> &arg){ +void ActionWithArguments::requestArguments(const vector<Value*> &arg) { plumed_massert(!lockRequestArguments,"requested argument list can only be changed in the prepare() method"); arguments=arg; clearDependencies(); std::string fullname,name; - for(unsigned i=0;i<arguments.size();i++){ - fullname=arguments[i]->getName(); - if(fullname.find(".")!=string::npos){ - std::size_t dot=fullname.find_first_of('.'); - name=fullname.substr(0,dot); - } else { - name=fullname; - } - ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>(name); - plumed_massert(action,"cannot find action named (in requestArguments - this is weird)" + name); - addDependency(action); + for(unsigned i=0; i<arguments.size(); i++) { + fullname=arguments[i]->getName(); + if(fullname.find(".")!=string::npos) { + std::size_t dot=fullname.find_first_of('.'); + name=fullname.substr(0,dot); + } else { + name=fullname; + } + ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>(name); + plumed_massert(action,"cannot find action named (in requestArguments - this is weird)" + name); + addDependency(action); } } @@ -243,21 +243,21 @@ ActionWithArguments::ActionWithArguments(const ActionOptions&ao): Action(ao), lockRequestArguments(false) { - if( keywords.exists("ARG") && !keywords.exists("DATA") ){ - vector<Value*> arg; - parseArgumentList("ARG",arg); + if( keywords.exists("ARG") && !keywords.exists("DATA") ) { + vector<Value*> arg; + parseArgumentList("ARG",arg); - if(!arg.empty()){ - log.printf(" with arguments"); - for(unsigned i=0;i<arg.size();i++) log.printf(" %s",arg[i]->getName().c_str()); - log.printf("\n"); - } - requestArguments(arg); + if(!arg.empty()) { + log.printf(" with arguments"); + for(unsigned i=0; i<arg.size(); i++) log.printf(" %s",arg[i]->getName().c_str()); + log.printf("\n"); + } + requestArguments(arg); } } -void ActionWithArguments::calculateNumericalDerivatives( ActionWithValue* a ){ - if(!a){ +void ActionWithArguments::calculateNumericalDerivatives( ActionWithValue* a ) { + if(!a) { a=dynamic_cast<ActionWithValue*>(this); plumed_massert(a,"cannot compute numerical derivatives for an action without values"); } @@ -265,24 +265,24 @@ void ActionWithArguments::calculateNumericalDerivatives( ActionWithValue* a ){ const int nval=a->getNumberOfComponents(); const int npar=arguments.size(); std::vector<double> value (nval*npar); - for(int i=0;i<npar;i++){ + for(int i=0; i<npar; i++) { double arg0=arguments[i]->get(); arguments[i]->set(arg0+sqrt(epsilon)); a->calculate(); arguments[i]->set(arg0); - for(int j=0;j<nval;j++){ + for(int j=0; j<nval; j++) { value[i*nval+j]=a->getOutputQuantity(j); } } a->calculate(); a->clearDerivatives(); - for(int j=0;j<nval;j++){ + for(int j=0; j<nval; j++) { Value* v=a->copyOutput(j); - if( v->hasDerivatives() ) for(int i=0;i<npar;i++) v->addDerivative(i,(value[i*nval+j]-a->getOutputQuantity(j))/sqrt(epsilon)); + if( v->hasDerivatives() ) for(int i=0; i<npar; i++) v->addDerivative(i,(value[i*nval+j]-a->getOutputQuantity(j))/sqrt(epsilon)); } } -double ActionWithArguments::getProjection(unsigned i,unsigned j)const{ +double ActionWithArguments::getProjection(unsigned i,unsigned j)const { plumed_massert(i<arguments.size()," making projections with an index which is too large"); plumed_massert(j<arguments.size()," making projections with an index which is too large"); const Value* v1=arguments[i]; @@ -290,8 +290,8 @@ double ActionWithArguments::getProjection(unsigned i,unsigned j)const{ return Value::projection(*v1,*v2); } -void ActionWithArguments::addForcesOnArguments( const std::vector<double>& forces ){ - for(unsigned i=0;i<arguments.size();++i) arguments[i]->addForce( forces[i] ); +void ActionWithArguments::addForcesOnArguments( const std::vector<double>& forces ) { + for(unsigned i=0; i<arguments.size(); ++i) arguments[i]->addForce( forces[i] ); } } diff --git a/src/core/ActionWithArguments.h b/src/core/ActionWithArguments.h index a4036f99c..47a14b760 100644 --- a/src/core/ActionWithArguments.h +++ b/src/core/ActionWithArguments.h @@ -26,16 +26,16 @@ #include "Value.h" #include <vector> -namespace PLMD{ +namespace PLMD { /** \ingroup MULTIINHERIT -This is used to create PLMD::Action objects that take the output from some other Action as input. +This is used to create PLMD::Action objects that take the output from some other Action as input. This is used in PLMD::Function and PLMD::Bias - PLMD::Action objects that inherit from PLMD::ActionWithArguments take + PLMD::Action objects that inherit from PLMD::ActionWithArguments take values and components calculated in other PLMD::Action objects and - use this information to calculate some new function. If you have - only one list of arguments you should use the reserved keyword <b> ARG </b> + use this information to calculate some new function. If you have + only one list of arguments you should use the reserved keyword <b> ARG </b> when you use parseArgumentList. */ @@ -60,7 +60,7 @@ public: virtual unsigned getNumberOfArguments() const ; /// Takes the difference taking into account pbc for arg i double difference(int, double, double) const; -/// Takes one value and brings it back into the pbc of argument i +/// Takes one value and brings it back into the pbc of argument i double bringBackInPbc(int i,double d1)const; /// Parse a list of arguments void parseArgumentList(const std::string&key,std::vector<Value*>&args); @@ -72,9 +72,9 @@ public: void addForcesOnArguments( const std::vector<double>& forces ); public: explicit ActionWithArguments(const ActionOptions&); - virtual ~ActionWithArguments(){} + virtual ~ActionWithArguments() {} /// Calculate the numerical derivatives -/// N.B. only pass an ActionWithValue to this routine if you know exactly what you +/// N.B. only pass an ActionWithValue to this routine if you know exactly what you /// are doing. The default will be correct for the vast majority of cases virtual void calculateNumericalDerivatives( ActionWithValue* a=NULL ); void lockRequests(); @@ -87,7 +87,7 @@ public: inline -Value* ActionWithArguments::getPntrToArgument( const unsigned n ){ +Value* ActionWithArguments::getPntrToArgument( const unsigned n ) { return arguments[n]; } @@ -97,27 +97,27 @@ double ActionWithArguments::getArgument(const unsigned n) const { } inline -unsigned ActionWithArguments::getNumberOfArguments()const{ +unsigned ActionWithArguments::getNumberOfArguments()const { return arguments.size(); } inline -double ActionWithArguments::difference(int i,double d1,double d2)const{ +double ActionWithArguments::difference(int i,double d1,double d2)const { return arguments[i]->difference(d1,d2); } inline -double ActionWithArguments::bringBackInPbc(int i,double d1)const{ +double ActionWithArguments::bringBackInPbc(int i,double d1)const { return arguments[i]->bringBackInPbc(d1); } inline -void ActionWithArguments::lockRequests(){ +void ActionWithArguments::lockRequests() { lockRequestArguments=true; } inline -void ActionWithArguments::unlockRequests(){ +void ActionWithArguments::unlockRequests() { lockRequestArguments=false; } diff --git a/src/core/ActionWithValue.cpp b/src/core/ActionWithValue.cpp index 1a8d82111..bc92a9410 100644 --- a/src/core/ActionWithValue.cpp +++ b/src/core/ActionWithValue.cpp @@ -24,32 +24,32 @@ #include "tools/OpenMP.h" using namespace std; -namespace PLMD{ +namespace PLMD { -void ActionWithValue::registerKeywords(Keywords& keys){ +void ActionWithValue::registerKeywords(Keywords& keys) { keys.setComponentsIntroduction("By default the value of the calculated quantity can be referenced elsewhere in the " "input file by using the label of the action. Alternatively this Action can be used " "to be used to calculate the following quantities by employing the keywords listed " - "below. These quanties can be referenced elsewhere in the input by using this Action's " + "below. These quanties can be referenced elsewhere in the input by using this Action's " "label followed by a dot and the name of the quantity required from the list below."); keys.addFlag("NUMERICAL_DERIVATIVES", false, "calculate the derivatives for these quantities numerically"); } -void ActionWithValue::noAnalyticalDerivatives(Keywords& keys){ - keys.remove("NUMERICAL_DERIVATIVES"); - keys.addFlag("NUMERICAL_DERIVATIVES",true,"analytical derivatives are not implemented for this keyword so numerical derivatives are always used"); +void ActionWithValue::noAnalyticalDerivatives(Keywords& keys) { + keys.remove("NUMERICAL_DERIVATIVES"); + keys.addFlag("NUMERICAL_DERIVATIVES",true,"analytical derivatives are not implemented for this keyword so numerical derivatives are always used"); } -void ActionWithValue::componentsAreNotOptional(Keywords& keys){ - keys.setComponentsIntroduction("By default this Action calculates the following quantities. These quanties can " - "be referenced elsewhere in the input by using this Action's label followed by a " - "dot and the name of the quantity required from the list below."); +void ActionWithValue::componentsAreNotOptional(Keywords& keys) { + keys.setComponentsIntroduction("By default this Action calculates the following quantities. These quanties can " + "be referenced elsewhere in the input by using this Action's label followed by a " + "dot and the name of the quantity required from the list below."); } -void ActionWithValue::useCustomisableComponents(Keywords& keys){ - keys.setComponentsIntroduction("The names of the components in this action can be customized by the user in the " - "actions input file. However, in addition to these customizable components the " - "following quantities will always be output"); +void ActionWithValue::useCustomisableComponents(Keywords& keys) { + keys.setComponentsIntroduction("The names of the components in this action can be customized by the user in the " + "actions input file. However, in addition to these customizable components the " + "following quantities will always be output"); } ActionWithValue::ActionWithValue(const ActionOptions&ao): @@ -61,35 +61,35 @@ ActionWithValue::ActionWithValue(const ActionOptions&ao): if(numericalDerivatives) log.printf(" using numerical derivatives\n"); } -ActionWithValue::~ActionWithValue(){ - for(unsigned i=0;i<values.size();++i)delete values[i]; +ActionWithValue::~ActionWithValue() { + for(unsigned i=0; i<values.size(); ++i)delete values[i]; } -void ActionWithValue::clearInputForces(){ - for(unsigned i=0;i<values.size();i++) values[i]->clearInputForce(); +void ActionWithValue::clearInputForces() { + for(unsigned i=0; i<values.size(); i++) values[i]->clearInputForce(); } -void ActionWithValue::clearDerivatives(){ +void ActionWithValue::clearDerivatives() { unsigned nt = OpenMP::getGoodNumThreads(values); #pragma omp parallel num_threads(nt) - { + { #pragma omp for - for(unsigned i=0;i<values.size();i++) values[i]->clearDerivatives(); + for(unsigned i=0; i<values.size(); i++) values[i]->clearDerivatives(); } -} +} // -- These are the routine for copying the value pointers to other classes -- // bool ActionWithValue::exists( const std::string& name ) const { - for(unsigned i=0;i<values.size();++i){ - if (values[i]->name==name) return true; + for(unsigned i=0; i<values.size(); ++i) { + if (values[i]->name==name) return true; } return false; } Value* ActionWithValue::copyOutput( const std::string& name ) const { - for(unsigned i=0;i<values.size();++i){ - if (values[i]->name==name) return values[i]; + for(unsigned i=0; i<values.size(); ++i) { + if (values[i]->name==name) return values[i]; } plumed_merror("there is no pointer with name " + name); return NULL; @@ -102,30 +102,30 @@ Value* ActionWithValue::copyOutput( const unsigned& n ) const { // -- HERE WE HAVE THE STUFF FOR THE DEFAULT VALUE -- // -void ActionWithValue::addValue(){ +void ActionWithValue::addValue() { plumed_massert(values.empty(),"You have already added the default value for this action"); values.push_back(new Value(this,getLabel(), false ) ); } -void ActionWithValue::addValueWithDerivatives(){ +void ActionWithValue::addValueWithDerivatives() { plumed_massert(values.empty(),"You have already added the default value for this action"); values.push_back(new Value(this,getLabel(), true ) ); } -void ActionWithValue::setNotPeriodic(){ +void ActionWithValue::setNotPeriodic() { plumed_massert(values.size()==1,"The number of components is not equal to one"); plumed_massert(values[0]->name==getLabel(), "The value you are trying to set is not the default"); values[0]->min=0; values[0]->max=0; values[0]->setupPeriodicity(); } -void ActionWithValue::setPeriodic( const std::string& min, const std::string& max ){ +void ActionWithValue::setPeriodic( const std::string& min, const std::string& max ) { plumed_massert(values.size()==1,"The number of components is not equal to one"); plumed_massert(values[0]->name==getLabel(), "The value you are trying to set is not the default"); values[0]->setDomain( min, max ); } -Value* ActionWithValue::getPntrToValue(){ +Value* ActionWithValue::getPntrToValue() { plumed_dbg_massert(values.size()==1,"The number of components is not equal to one"); plumed_dbg_massert(values[0]->name==getLabel(), "The value you are trying to retrieve is not the default"); return values[0]; @@ -133,34 +133,34 @@ Value* ActionWithValue::getPntrToValue(){ // -- HERE WE HAVE THE STUFF FOR NAMED VALUES / COMPONENTS -- // -void ActionWithValue::addComponent( const std::string& name ){ - if( !keywords.outputComponentExists(name,true) ){ - warning("a description of component " + name + " has not been added to the manual. Components should be registered like keywords in " - "registerKeywords as described in the developer docs."); +void ActionWithValue::addComponent( const std::string& name ) { + if( !keywords.outputComponentExists(name,true) ) { + warning("a description of component " + name + " has not been added to the manual. Components should be registered like keywords in " + "registerKeywords as described in the developer docs."); } std::string thename; thename=getLabel() + "." + name; - for(unsigned i=0;i<values.size();++i){ - plumed_massert(values[i]->name!=getLabel(),"Cannot mix single values with components"); - plumed_massert(values[i]->name!=thename&&name!="bias","Since PLUMED 2.3 the component 'bias' is automatically added to all biases by the general constructor!\n" - "Remove the line addComponent(\"bias\") from your bias."); - plumed_massert(values[i]->name!=thename,"there is already a value with this name"); + for(unsigned i=0; i<values.size(); ++i) { + plumed_massert(values[i]->name!=getLabel(),"Cannot mix single values with components"); + plumed_massert(values[i]->name!=thename&&name!="bias","Since PLUMED 2.3 the component 'bias' is automatically added to all biases by the general constructor!\n" + "Remove the line addComponent(\"bias\") from your bias."); + plumed_massert(values[i]->name!=thename,"there is already a value with this name"); } values.push_back(new Value(this,thename, false ) ); std::string msg=" added component to this action: "+thename+" \n"; log.printf(msg.c_str()); } -void ActionWithValue::addComponentWithDerivatives( const std::string& name ){ - if( !keywords.outputComponentExists(name,true) ){ - warning("a description of component " + name + " has not been added to the manual. Components should be registered like keywords in " - "registerKeywords as described in the developer doc."); +void ActionWithValue::addComponentWithDerivatives( const std::string& name ) { + if( !keywords.outputComponentExists(name,true) ) { + warning("a description of component " + name + " has not been added to the manual. Components should be registered like keywords in " + "registerKeywords as described in the developer doc."); } std::string thename; thename=getLabel() + "." + name; - for(unsigned i=0;i<values.size();++i){ - plumed_massert(values[i]->name!=getLabel(),"Cannot mix single values with components"); - plumed_massert(values[i]->name!=thename&&name!="bias","Since PLUMED 2.3 the component 'bias' is automatically added to all biases by the general constructor!\n" - "Remove the line addComponentWithDerivatives(\"bias\") from your bias."); - plumed_massert(values[i]->name!=thename,"there is already a value with this name"); + for(unsigned i=0; i<values.size(); ++i) { + plumed_massert(values[i]->name!=getLabel(),"Cannot mix single values with components"); + plumed_massert(values[i]->name!=thename&&name!="bias","Since PLUMED 2.3 the component 'bias' is automatically added to all biases by the general constructor!\n" + "Remove the line addComponentWithDerivatives(\"bias\") from your bias."); + plumed_massert(values[i]->name!=thename,"there is already a value with this name"); } values.push_back(new Value(this,thename, true ) ); std::string msg=" added component to this action: "+thename+" \n"; @@ -170,8 +170,8 @@ void ActionWithValue::addComponentWithDerivatives( const std::string& name ){ int ActionWithValue::getComponent( const std::string& name ) const { plumed_massert( !exists( getLabel() ), "You should not be calling this routine if you are using a value"); std::string thename; thename=getLabel() + "." + name; - for(unsigned i=0;i<values.size();++i){ - if (values[i]->name==thename) return i; + for(unsigned i=0; i<values.size(); ++i) { + if (values[i]->name==thename) return i; } plumed_merror("there is no component with name " + name); return -1; @@ -179,55 +179,55 @@ int ActionWithValue::getComponent( const std::string& name ) const { std::string ActionWithValue::getComponentsList( ) const { std::string complist; - for(unsigned i=0;i<values.size();++i){ - complist+=values[i]->name+" "; + for(unsigned i=0; i<values.size(); ++i) { + complist+=values[i]->name+" "; } return complist; } std::vector<std::string> ActionWithValue::getComponentsVector( ) const { std::vector<std::string> complist; - for(unsigned i=0;i<values.size();++i){ - complist.push_back(values[i]->name); + for(unsigned i=0; i<values.size(); ++i) { + complist.push_back(values[i]->name); } return complist; } -void ActionWithValue::componentIsNotPeriodic( const std::string& name ){ +void ActionWithValue::componentIsNotPeriodic( const std::string& name ) { int kk=getComponent(name); values[kk]->min=0; values[kk]->max=0; values[kk]->setupPeriodicity(); } -void ActionWithValue::componentIsPeriodic( const std::string& name, const std::string& min, const std::string& max ){ +void ActionWithValue::componentIsPeriodic( const std::string& name, const std::string& min, const std::string& max ) { int kk=getComponent(name); values[kk]->setDomain(min,max); } -void ActionWithValue::setGradientsIfNeeded(){ +void ActionWithValue::setGradientsIfNeeded() { if(isOptionOn("GRADIENTS")) { - for(unsigned i=0;i<values.size();i++) values[i]->setGradients(); + for(unsigned i=0; i<values.size(); i++) values[i]->setGradients(); } } -void ActionWithValue::turnOnDerivatives(){ +void ActionWithValue::turnOnDerivatives() { // Turn on the derivatives noderiv=false; - // Resize the derivatives - for(unsigned i=0;i<values.size();++i) values[i]->resizeDerivatives( getNumberOfDerivatives() ); + // Resize the derivatives + for(unsigned i=0; i<values.size(); ++i) values[i]->resizeDerivatives( getNumberOfDerivatives() ); // And turn on the derivatives in all actions on which we are dependent - for(unsigned i=0;i<getDependencies().size();++i){ - ActionWithValue* vv=dynamic_cast<ActionWithValue*>( getDependencies()[i] ); - if(vv) vv->turnOnDerivatives(); + for(unsigned i=0; i<getDependencies().size(); ++i) { + ActionWithValue* vv=dynamic_cast<ActionWithValue*>( getDependencies()[i] ); + if(vv) vv->turnOnDerivatives(); } } -Value* ActionWithValue::getPntrToComponent( const std::string& name ){ +Value* ActionWithValue::getPntrToComponent( const std::string& name ) { int kk=getComponent(name); - return values[kk]; + return values[kk]; } -Value* ActionWithValue::getPntrToComponent( int n ){ +Value* ActionWithValue::getPntrToComponent( int n ) { plumed_dbg_massert(n<values.size(),"you have requested a pointer that is out of bounds"); return values[n]; } diff --git a/src/core/ActionWithValue.h b/src/core/ActionWithValue.h index 74c39411a..9d13f30d1 100644 --- a/src/core/ActionWithValue.h +++ b/src/core/ActionWithValue.h @@ -27,12 +27,12 @@ #include "tools/Exception.h" #include <vector> -namespace PLMD{ +namespace PLMD { /** \ingroup MULTIINHERIT -Used to create a PLMD::Action that has some scalar or vectorial output that may or may not have some derivatives. -This is used for PLMD::Bias, PLMD::Colvar and PLMD::Function +Used to create a PLMD::Action that has some scalar or vectorial output that may or may not have some derivatives. +This is used for PLMD::Bias, PLMD::Colvar and PLMD::Function The vast majority of the PLMD::Action objects that are implemented in plumed calculate some quantity or a set of quantities. This could be @@ -43,26 +43,26 @@ quantities between PLMD::Actions. When you are deciding what quantities your new PLMD::Action will need to store using PLMD::ActionWithValue you must ask yourself the following two questions: -- Do I need to differentiate my output quantities -- Is my PLMD::Action calculating a single thing or does the output have multiple components +- Do I need to differentiate my output quantities +- Is my PLMD::Action calculating a single thing or does the output have multiple components If the answer to the first of these questions is yes then you must setup your values -you using either PLMD::ActionWithValue::addValueWithDerivatives() or -PLMD::ActionWithValue::addComponentWithDerivatives. If the answer is no you +you using either PLMD::ActionWithValue::addValueWithDerivatives() or +PLMD::ActionWithValue::addComponentWithDerivatives. If the answer is no you can set up values using PLMD::ActionWithValue::addValue() or PLMD::ActionWithValue::addComponent(). The precise routine you use to setup your values will depend on your answer to the -second question. As you are probably aware if the output of your PLMD::Action is a -single quantity you can reference that quantity in the input file using the label of the -PLMD::Action it was calculated in. If your action <b> outputs only one quantity </b> -we call that quantity the <b> value </b> of the Action. To set the <b> value </b> and get pointers to it -you should <b> use the set of routines that have the word value in the name </b>. If, by contrast, +second question. As you are probably aware if the output of your PLMD::Action is a +single quantity you can reference that quantity in the input file using the label of the +PLMD::Action it was calculated in. If your action <b> outputs only one quantity </b> +we call that quantity the <b> value </b> of the Action. To set the <b> value </b> and get pointers to it +you should <b> use the set of routines that have the word value in the name </b>. If, by contrast, your PLMD::Action calculates multiple quantities then these quantities are referenced in input using the -label.component syntax. We refer to these <b> multiple quantities </b> the <b> components </b> +label.component syntax. We refer to these <b> multiple quantities </b> the <b> components </b> of the PLMD::Action. Perhaps unsurprisingly, when you manipulate the <b> components </b> of an PLMD::Action you should use <b> the routines with the word component in the name. </b> */ -class ActionWithValue : +class ActionWithValue : public virtual Action { private: @@ -112,7 +112,7 @@ public: explicit ActionWithValue(const ActionOptions&ao); ~ActionWithValue(); -/// Register all the relevant keywords for the action +/// Register all the relevant keywords for the action static void registerKeywords( Keywords& keys ); /// Insist that numerical derivatives should always be used for an action and make this fact appear in the manual static void noAnalyticalDerivatives(Keywords& keys); @@ -125,7 +125,7 @@ public: /// Get the value of one of the components of the PLMD::Action double getOutputQuantity( const unsigned j ) const ; /// Get the value with a specific name (N.B. if there is no such value this returns zero) - double getOutputQuantity( const std::string& name ) const ; + double getOutputQuantity( const std::string& name ) const ; // --- Routines for passing stuff to ActionWithArguments -- // @@ -133,14 +133,14 @@ public: /// You should not use it when manipulating components. bool exists( const std::string& name ) const; /// Return a pointer to the value with name (this is used to retrieve values in other PLMD::Actions) -/// You should NEVER use this routine to refer to the components of your PLMD::Action. Use +/// You should NEVER use this routine to refer to the components of your PLMD::Action. Use /// getPntrToComponent instead. Value* copyOutput( const std::string&name ) const; /// Return a pointer to the value with this number (this is used to retrieve values in other PLMD::Actions) -/// You should NEVER use this routine to refer to the components of your PLMD::Action. Use +/// You should NEVER use this routine to refer to the components of your PLMD::Action. Use /// getPntrToComponent instead. Value* copyOutput( const unsigned& n ) const; -/// get a string that contains all the available components +/// get a string that contains all the available components std::string getComponentsList( ) const ; /// get a vector that contains the label for all the components std::vector<std::string> getComponentsVector( ) const ; @@ -154,17 +154,17 @@ public: void clearInputForces(); /// Clear the derivatives of values wrt parameters virtual void clearDerivatives(); -/// Calculate the gradients and store them for all the values (need for projections) +/// Calculate the gradients and store them for all the values (need for projections) void setGradientsIfNeeded(); /// Set the value void setValue(Value*,double); /// Check if numerical derivatives should be used bool checkNumericalDerivatives() const ; -/// This forces the class to use numerical derivatives +/// This forces the class to use numerical derivatives void useNumericalDerivatives(); // These are things for using vectors of values as fields - virtual void checkFieldsAllowed(){ error("cannot use this action as a field"); } - virtual unsigned getNumberOfDerivatives()=0; + virtual void checkFieldsAllowed() { error("cannot use this action as a field"); } + virtual unsigned getNumberOfDerivatives()=0; /// Activate the calculation of derivatives virtual void turnOnDerivatives(); }; @@ -178,14 +178,14 @@ double ActionWithValue::getOutputQuantity(const unsigned j) const { inline double ActionWithValue::getOutputQuantity( const std::string& name ) const { std::string thename; thename=getLabel() + "." + name; - for(unsigned i=0;i<values.size();++i){ + for(unsigned i=0; i<values.size(); ++i) { if( values[i]->name==thename ) return values[i]->value; } return 0.0; } inline -void ActionWithValue::setValue(const double& d){ +void ActionWithValue::setValue(const double& d) { plumed_massert(values.size()==1, "cannot use setValue in multi-component actions"); plumed_massert(values[0]->name==getLabel(), "The value you are trying to set is not the default"); values[0]->set(d); @@ -197,7 +197,7 @@ int ActionWithValue::getNumberOfComponents() const { } inline -void ActionWithValue::useNumericalDerivatives(){ +void ActionWithValue::useNumericalDerivatives() { plumed_massert( keywords.exists("NUMERICAL_DERIVATIVES"), "numerical derivatives are not permitted for this action" ); numericalDerivatives=true; } @@ -210,7 +210,7 @@ bool ActionWithValue::checkNumericalDerivatives() const { inline bool ActionWithValue::doNotCalculateDerivatives() const { return noderiv; -} +} diff --git a/src/core/ActionWithVirtualAtom.cpp b/src/core/ActionWithVirtualAtom.cpp index da6d8a6af..668ea7e79 100644 --- a/src/core/ActionWithVirtualAtom.cpp +++ b/src/core/ActionWithVirtualAtom.cpp @@ -24,9 +24,9 @@ using namespace std; -namespace PLMD{ +namespace PLMD { -void ActionWithVirtualAtom::registerKeywords(Keywords& keys){ +void ActionWithVirtualAtom::registerKeywords(Keywords& keys) { Action::registerKeywords(keys); ActionAtomistic::registerKeywords(keys); keys.add("atoms","ATOMS","the list of atoms which are involved the virtual atom's definition"); @@ -41,71 +41,71 @@ ActionWithVirtualAtom::ActionWithVirtualAtom(const ActionOptions&ao): log.printf(" serial associated to this virtual atom is %u\n",index.serial()); } -ActionWithVirtualAtom::~ActionWithVirtualAtom(){ +ActionWithVirtualAtom::~ActionWithVirtualAtom() { atoms.removeVirtualAtom(this); } -void ActionWithVirtualAtom::apply(){ +void ActionWithVirtualAtom::apply() { Vector & f(atoms.forces[index.index()]); - for(unsigned i=0;i<getNumberOfAtoms();i++) modifyForces()[i]=matmul(derivatives[i],f); + for(unsigned i=0; i<getNumberOfAtoms(); i++) modifyForces()[i]=matmul(derivatives[i],f); Tensor & v(modifyVirial()); - for(unsigned i=0;i<3;i++) v+=boxDerivatives[i]*f[i]; + for(unsigned i=0; i<3; i++) v+=boxDerivatives[i]*f[i]; f.zero(); // after propagating the force to the atoms used to compute the vatom, we reset this to zero - // this is necessary to avoid double counting if then one tries to compute the total force on the c.o.m. of the system. - // notice that this is currently done in FIT_TO_TEMPLATE + // this is necessary to avoid double counting if then one tries to compute the total force on the c.o.m. of the system. + // notice that this is currently done in FIT_TO_TEMPLATE } -void ActionWithVirtualAtom::requestAtoms(const std::vector<AtomNumber> & a){ +void ActionWithVirtualAtom::requestAtoms(const std::vector<AtomNumber> & a) { ActionAtomistic::requestAtoms(a); derivatives.resize(a.size()); } -void ActionWithVirtualAtom::setGradients(){ +void ActionWithVirtualAtom::setGradients() { gradients.clear(); - for(unsigned i=0;i<getNumberOfAtoms();i++){ + for(unsigned i=0; i<getNumberOfAtoms(); i++) { AtomNumber an=getAbsoluteIndex(i); - // this case if the atom is a virtual one - if(atoms.isVirtualAtom(an)){ + // this case if the atom is a virtual one + if(atoms.isVirtualAtom(an)) { const ActionWithVirtualAtom* a=atoms.getVirtualAtomsAction(an); - for(const auto & p : a->gradients){ + for(const auto & p : a->gradients) { gradients[p.first]+=matmul(derivatives[i],p.second); } - // this case if the atom is a normal one + // this case if the atom is a normal one } else { gradients[an]+=derivatives[i]; } } } -void ActionWithVirtualAtom::setBoxDerivatives(const std::vector<Tensor> &d){ +void ActionWithVirtualAtom::setBoxDerivatives(const std::vector<Tensor> &d) { boxDerivatives=d; plumed_assert(d.size()==3); // Subtract the trivial part coming from a distorsion applied to the ghost atom first. // Notice that this part alone should exactly cancel the already accumulated virial // due to forces on this atom. Vector pos=atoms.positions[index.index()]; - for(unsigned i=0;i<3;i++) for(unsigned j=0;j<3;j++) boxDerivatives[j][i][j]+=pos[i]; + for(unsigned i=0; i<3; i++) for(unsigned j=0; j<3; j++) boxDerivatives[j][i][j]+=pos[i]; } -void ActionWithVirtualAtom::setBoxDerivativesNoPbc(){ +void ActionWithVirtualAtom::setBoxDerivativesNoPbc() { std::vector<Tensor> bd(3); - for(unsigned i=0;i<3;i++) for(unsigned j=0;j<3;j++) for(unsigned k=0;k<3;k++){ + for(unsigned i=0; i<3; i++) for(unsigned j=0; j<3; j++) for(unsigned k=0; k<3; k++) { // Notice that this expression is very similar to the one used in Colvar::setBoxDerivativesNoPbc(). // Indeed, we have the negative of a sum over dependent atoms (l) of the external product between positions // and derivatives. Notice that this only works only when Pbc have not been used to compute // derivatives. - for(unsigned l=0;l<getNumberOfAtoms();l++){ - bd[k][i][j]-=getPosition(l)[i]*derivatives[l][j][k]; - } - } + for(unsigned l=0; l<getNumberOfAtoms(); l++) { + bd[k][i][j]-=getPosition(l)[i]*derivatives[l][j][k]; + } + } setBoxDerivatives(bd); } -void ActionWithVirtualAtom::setGradientsIfNeeded(){ - if(isOptionOn("GRADIENTS")) { - setGradients() ; +void ActionWithVirtualAtom::setGradientsIfNeeded() { + if(isOptionOn("GRADIENTS")) { + setGradients() ; } } diff --git a/src/core/ActionWithVirtualAtom.h b/src/core/ActionWithVirtualAtom.h index 9824f8af9..74bf868ae 100644 --- a/src/core/ActionWithVirtualAtom.h +++ b/src/core/ActionWithVirtualAtom.h @@ -28,7 +28,7 @@ #include "tools/Tensor.h" #include "Atoms.h" -namespace PLMD{ +namespace PLMD { /** \ingroup INHERIT @@ -85,32 +85,32 @@ public: }; inline -AtomNumber ActionWithVirtualAtom::getIndex()const{ +AtomNumber ActionWithVirtualAtom::getIndex()const { return index; } inline -void ActionWithVirtualAtom::setPosition(const Vector & pos){ +void ActionWithVirtualAtom::setPosition(const Vector & pos) { atoms.positions[index.index()]=pos; } inline -void ActionWithVirtualAtom::setMass(double m){ +void ActionWithVirtualAtom::setMass(double m) { atoms.masses[index.index()]=m; } inline -void ActionWithVirtualAtom::setCharge(double c){ +void ActionWithVirtualAtom::setCharge(double c) { atoms.charges[index.index()]=c; } inline -void ActionWithVirtualAtom::setAtomsDerivatives(const std::vector<Tensor> &d){ +void ActionWithVirtualAtom::setAtomsDerivatives(const std::vector<Tensor> &d) { derivatives=d; } inline -const std::map<AtomNumber,Tensor> & ActionWithVirtualAtom::getGradients()const{ +const std::map<AtomNumber,Tensor> & ActionWithVirtualAtom::getGradients()const { return gradients; } diff --git a/src/core/Atoms.cpp b/src/core/Atoms.cpp index ec0ba9c58..8841bbefe 100644 --- a/src/core/Atoms.cpp +++ b/src/core/Atoms.cpp @@ -67,111 +67,111 @@ Atoms::Atoms(PlumedMain&plumed): mdatoms=MDAtomsBase::create(sizeof(double)); } -Atoms::~Atoms(){ - if(actions.size()>0){ +Atoms::~Atoms() { + if(actions.size()>0) { std::cerr<<"WARNING: there is some inconsistency in action added to atoms, as some of them were not properly destroyed. This might indicate an internal bug!!\n"; } delete mdatoms; delete &pbc; } -void Atoms::startStep(){ +void Atoms::startStep() { collectEnergy=false; energyHasBeenSet=false; positionsHaveBeenSet=0; massesHaveBeenSet=false; chargesHaveBeenSet=false; boxHasBeenSet=false; forcesHaveBeenSet=0; virialHasBeenSet=false; dataCanBeSet=true; } -void Atoms::setBox(void*p){ +void Atoms::setBox(void*p) { mdatoms->setBox(p); Tensor b; mdatoms->getBox(b); boxHasBeenSet=true; } -void Atoms::setPositions(void*p){ - plumed_massert( dataCanBeSet ,"setPositions must be called after setStep in MD code interface"); +void Atoms::setPositions(void*p) { + plumed_massert( dataCanBeSet,"setPositions must be called after setStep in MD code interface"); plumed_massert( p || gatindex.size()==0, "NULL position pointer with non-zero local atoms"); mdatoms->setp(p); positionsHaveBeenSet=3; } -void Atoms::setMasses(void*p){ - plumed_massert( dataCanBeSet ,"setMasses must be called after setStep in MD code interface"); +void Atoms::setMasses(void*p) { + plumed_massert( dataCanBeSet,"setMasses must be called after setStep in MD code interface"); plumed_massert( p || gatindex.size()==0, "NULL mass pointer with non-zero local atoms"); mdatoms->setm(p); massesHaveBeenSet=true; } -void Atoms::setCharges(void*p){ +void Atoms::setCharges(void*p) { plumed_massert( dataCanBeSet, "setCharges must be called after setStep in MD code interface"); plumed_massert( p || gatindex.size()==0, "NULL charges pointer with non-zero local atoms"); mdatoms->setc(p); chargesHaveBeenSet=true; } -void Atoms::setVirial(void*p){ - plumed_massert( dataCanBeSet ,"setVirial must be called after setStep in MD code interface"); +void Atoms::setVirial(void*p) { + plumed_massert( dataCanBeSet,"setVirial must be called after setStep in MD code interface"); mdatoms->setVirial(p); virialHasBeenSet=true; - + } -void Atoms::setEnergy(void*p){ - plumed_massert( dataCanBeSet ,"setEnergy must be called after setStep in MD code interface"); +void Atoms::setEnergy(void*p) { + plumed_massert( dataCanBeSet,"setEnergy must be called after setStep in MD code interface"); MD2double(p,md_energy); md_energy*=MDUnits.getEnergy()/units.getEnergy(); energyHasBeenSet=true; } -void Atoms::setForces(void*p){ - plumed_massert( dataCanBeSet ,"setForces must be called after setStep in MD code interface"); +void Atoms::setForces(void*p) { + plumed_massert( dataCanBeSet,"setForces must be called after setStep in MD code interface"); plumed_massert( p || gatindex.size()==0, "NULL force pointer with non-zero local atoms"); forcesHaveBeenSet=3; mdatoms->setf(p); } -void Atoms::setPositions(void*p,int i){ - plumed_massert( dataCanBeSet ,"setPositions must be called after setStep in MD code interface"); +void Atoms::setPositions(void*p,int i) { + plumed_massert( dataCanBeSet,"setPositions must be called after setStep in MD code interface"); plumed_massert( p || gatindex.size()==0, "NULL positions pointer with non-zero local atoms"); mdatoms->setp(p,i); positionsHaveBeenSet++; } -void Atoms::setForces(void*p,int i){ - plumed_massert( dataCanBeSet ,"setForces must be called after setStep in MD code interface"); +void Atoms::setForces(void*p,int i) { + plumed_massert( dataCanBeSet,"setForces must be called after setStep in MD code interface"); plumed_massert( p || gatindex.size()==0, "NULL force pointer with non-zero local atoms"); mdatoms->setf(p,i); forcesHaveBeenSet++; } -void Atoms::share(){ +void Atoms::share() { std::set<AtomNumber> unique; // At first step I scatter all the atoms so as to store their mass and charge // Notice that this works with the assumption that charges and masses are // not changing during the simulation! - if(!massAndChargeOK && shareMassAndChargeOnlyAtFirstStep){ + if(!massAndChargeOK && shareMassAndChargeOnlyAtFirstStep) { shareAll(); return; } - for(unsigned i=0;i<actions.size();i++) if(actions[i]->isActive()) { - if(dd && shuffledAtoms>0){ - unique.insert(actions[i]->getUnique().begin(),actions[i]->getUnique().end()); + for(unsigned i=0; i<actions.size(); i++) if(actions[i]->isActive()) { + if(dd && shuffledAtoms>0) { + unique.insert(actions[i]->getUnique().begin(),actions[i]->getUnique().end()); + } + if(!actions[i]->getUnique().empty()) atomsNeeded=true; } - if(!actions[i]->getUnique().empty()) atomsNeeded=true; - } share(unique); } -void Atoms::shareAll(){ +void Atoms::shareAll() { std::set<AtomNumber> unique; if(dd && shuffledAtoms>0) - for(int i=0;i<natoms;i++) unique.insert(AtomNumber::index(i)); + for(int i=0; i<natoms; i++) unique.insert(AtomNumber::index(i)); atomsNeeded=true; share(unique); } -void Atoms::share(const std::set<AtomNumber>& unique){ +void Atoms::share(const std::set<AtomNumber>& unique) { plumed_assert( positionsHaveBeenSet==3 && massesHaveBeenSet ); virial.zero(); - if(zeroallforces || int(gatindex.size())==natoms){ - for(int i=0;i<natoms;i++) forces[i].zero(); + if(zeroallforces || int(gatindex.size())==natoms) { + for(int i=0; i<natoms; i++) forces[i].zero(); } else { - for(unsigned i=0;i<gatindex.size();i++) forces[gatindex[i]].zero(); + for(unsigned i=0; i<gatindex.size(); i++) forces[gatindex[i]].zero(); } - for(unsigned i=getNatoms();i<positions.size();i++) forces[i].zero(); // virtual atoms + for(unsigned i=getNatoms(); i<positions.size(); i++) forces[i].zero(); // virtual atoms forceOnEnergy=0.0; mdatoms->getBox(box); @@ -179,7 +179,7 @@ void Atoms::share(const std::set<AtomNumber>& unique){ atomsNeeded=false; - if(int(gatindex.size())==natoms && shuffledAtoms==0){ + if(int(gatindex.size())==natoms && shuffledAtoms==0) { // faster version, which retrieves all atoms mdatoms->getPositions(0,natoms,positions); } else { @@ -188,7 +188,7 @@ void Atoms::share(const std::set<AtomNumber>& unique){ } // how many double per atom should be scattered: int ndata=3; - if(!massAndChargeOK){ + if(!massAndChargeOK) { ndata=5; masses.assign(masses.size(),NAN); charges.assign(charges.size(),NAN); @@ -196,34 +196,34 @@ void Atoms::share(const std::set<AtomNumber>& unique){ mdatoms->getMasses(gatindex,masses); } - if(dd && shuffledAtoms>0){ - if(dd.async){ - for(unsigned i=0;i<dd.mpi_request_positions.size();i++) dd.mpi_request_positions[i].wait(); - for(unsigned i=0;i<dd.mpi_request_index.size();i++) dd.mpi_request_index[i].wait(); + if(dd && shuffledAtoms>0) { + if(dd.async) { + for(unsigned i=0; i<dd.mpi_request_positions.size(); i++) dd.mpi_request_positions[i].wait(); + for(unsigned i=0; i<dd.mpi_request_index.size(); i++) dd.mpi_request_index[i].wait(); } int count=0; - for(const auto & p : unique){ - if(dd.g2l[p.index()]>=0){ + for(const auto & p : unique) { + if(dd.g2l[p.index()]>=0) { dd.indexToBeSent[count]=p.index(); dd.positionsToBeSent[ndata*count+0]=positions[p.index()][0]; dd.positionsToBeSent[ndata*count+1]=positions[p.index()][1]; dd.positionsToBeSent[ndata*count+2]=positions[p.index()][2]; - if(!massAndChargeOK){ + if(!massAndChargeOK) { dd.positionsToBeSent[ndata*count+3]=masses[p.index()]; dd.positionsToBeSent[ndata*count+4]=charges[p.index()]; } count++; } } - if(dd.async){ + if(dd.async) { asyncSent=true; dd.mpi_request_positions.resize(dd.Get_size()); dd.mpi_request_index.resize(dd.Get_size()); - for(int i=0;i<dd.Get_size();i++){ + for(int i=0; i<dd.Get_size(); i++) { dd.mpi_request_index[i]=dd.Isend(&dd.indexToBeSent[0],count,i,666); dd.mpi_request_positions[i]=dd.Isend(&dd.positionsToBeSent[0],ndata*count,i,667); } - }else{ + } else { const int n=(dd.Get_size()); vector<int> counts(n); vector<int> displ(n); @@ -231,17 +231,17 @@ void Atoms::share(const std::set<AtomNumber>& unique){ vector<int> displ5(n); dd.Allgather(count,counts); displ[0]=0; - for(int i=1;i<n;++i) displ[i]=displ[i-1]+counts[i-1]; - for(int i=0;i<n;++i) counts5[i]=counts[i]*ndata; - for(int i=0;i<n;++i) displ5[i]=displ[i]*ndata; + for(int i=1; i<n; ++i) displ[i]=displ[i-1]+counts[i-1]; + for(int i=0; i<n; ++i) counts5[i]=counts[i]*ndata; + for(int i=0; i<n; ++i) displ5[i]=displ[i]*ndata; dd.Allgatherv(&dd.indexToBeSent[0],count,&dd.indexToBeReceived[0],&counts[0],&displ[0]); dd.Allgatherv(&dd.positionsToBeSent[0],ndata*count,&dd.positionsToBeReceived[0],&counts5[0],&displ5[0]); int tot=displ[n-1]+counts[n-1]; - for(int i=0;i<tot;i++){ + for(int i=0; i<tot; i++) { positions[dd.indexToBeReceived[i]][0]=dd.positionsToBeReceived[ndata*i+0]; positions[dd.indexToBeReceived[i]][1]=dd.positionsToBeReceived[ndata*i+1]; positions[dd.indexToBeReceived[i]][2]=dd.positionsToBeReceived[ndata*i+2]; - if(!massAndChargeOK){ + if(!massAndChargeOK) { masses[dd.indexToBeReceived[i]] =dd.positionsToBeReceived[ndata*i+3]; charges[dd.indexToBeReceived[i]] =dd.positionsToBeReceived[ndata*i+4]; } @@ -250,35 +250,35 @@ void Atoms::share(const std::set<AtomNumber>& unique){ } } -void Atoms::wait(){ +void Atoms::wait() { dataCanBeSet=false; // Everything should be set by this stage // How many double per atom should be scattered int ndata=3; if(!massAndChargeOK)ndata=5; - if(dd){ + if(dd) { dd.Bcast(box,0); } pbc.setBox(box); if(collectEnergy) energy=md_energy; - if(dd && shuffledAtoms>0){ + if(dd && shuffledAtoms>0) { // receive toBeReceived - if(asyncSent){ + if(asyncSent) { Communicator::Status status; int count=0; - for(int i=0;i<dd.Get_size();i++){ + for(int i=0; i<dd.Get_size(); i++) { dd.Recv(&dd.indexToBeReceived[count],dd.indexToBeReceived.size()-count,i,666,status); int c=status.Get_count<int>(); dd.Recv(&dd.positionsToBeReceived[ndata*count],dd.positionsToBeReceived.size()-ndata*count,i,667); count+=c; } - for(int i=0;i<count;i++){ + for(int i=0; i<count; i++) { positions[dd.indexToBeReceived[i]][0]=dd.positionsToBeReceived[ndata*i+0]; positions[dd.indexToBeReceived[i]][1]=dd.positionsToBeReceived[ndata*i+1]; positions[dd.indexToBeReceived[i]][2]=dd.positionsToBeReceived[ndata*i+2]; - if(!massAndChargeOK){ + if(!massAndChargeOK) { masses[dd.indexToBeReceived[i]] =dd.positionsToBeReceived[ndata*i+3]; charges[dd.indexToBeReceived[i]] =dd.positionsToBeReceived[ndata*i+4]; } @@ -292,50 +292,50 @@ void Atoms::wait(){ if(shareMassAndChargeOnlyAtFirstStep) massAndChargeOK=true; } -void Atoms::updateForces(){ +void Atoms::updateForces() { plumed_assert( forcesHaveBeenSet==3 ); - if(forceOnEnergy*forceOnEnergy>epsilon){ - double alpha=1.0-forceOnEnergy; - mdatoms->rescaleForces(gatindex,alpha); + if(forceOnEnergy*forceOnEnergy>epsilon) { + double alpha=1.0-forceOnEnergy; + mdatoms->rescaleForces(gatindex,alpha); } mdatoms->updateForces(gatindex,forces); - if( !plumed.novirial && dd.Get_rank()==0 ){ - plumed_assert( virialHasBeenSet ); - mdatoms->updateVirial(virial); + if( !plumed.novirial && dd.Get_rank()==0 ) { + plumed_assert( virialHasBeenSet ); + mdatoms->updateVirial(virial); } } -void Atoms::setNatoms(int n){ +void Atoms::setNatoms(int n) { natoms=n; positions.resize(n); forces.resize(n); masses.resize(n); charges.resize(n); gatindex.resize(n); - for(unsigned i=0;i<gatindex.size();i++) gatindex[i]=i; + for(unsigned i=0; i<gatindex.size(); i++) gatindex[i]=i; } -void Atoms::add(const ActionAtomistic*a){ +void Atoms::add(const ActionAtomistic*a) { actions.push_back(a); } -void Atoms::remove(const ActionAtomistic*a){ +void Atoms::remove(const ActionAtomistic*a) { auto f=find(actions.begin(),actions.end(),a); plumed_massert(f!=actions.end(),"cannot remove an action registered to atoms"); actions.erase(f); } -void Atoms::DomainDecomposition::enable(Communicator& c){ +void Atoms::DomainDecomposition::enable(Communicator& c) { on=true; Set_comm(c.Get_comm()); async=Get_size()<10; } -void Atoms::setAtomsNlocal(int n){ +void Atoms::setAtomsNlocal(int n) { gatindex.resize(n); - if(dd){ + if(dd) { dd.g2l.resize(natoms,-1); // Since these vectors are sent with MPI by using e.g. // &dd.positionsToBeSent[0] @@ -349,178 +349,178 @@ void Atoms::setAtomsNlocal(int n){ }; } -void Atoms::setAtomsGatindex(int*g,bool fortran){ +void Atoms::setAtomsGatindex(int*g,bool fortran) { plumed_massert( g || gatindex.size()==0, "NULL gatindex pointer with non-zero local atoms"); ddStep=plumed.getStep(); - if(fortran){ - for(unsigned i=0;i<gatindex.size();i++) gatindex[i]=g[i]-1; + if(fortran) { + for(unsigned i=0; i<gatindex.size(); i++) gatindex[i]=g[i]-1; } else { - for(unsigned i=0;i<gatindex.size();i++) gatindex[i]=g[i]; + for(unsigned i=0; i<gatindex.size(); i++) gatindex[i]=g[i]; } - for(unsigned i=0;i<dd.g2l.size();i++) dd.g2l[i]=-1; - if( gatindex.size()==natoms ){ - shuffledAtoms=0; - for(unsigned i=0;i<gatindex.size();i++){ - if( gatindex[i]!=i ){ shuffledAtoms=1; break; } - } + for(unsigned i=0; i<dd.g2l.size(); i++) dd.g2l[i]=-1; + if( gatindex.size()==natoms ) { + shuffledAtoms=0; + for(unsigned i=0; i<gatindex.size(); i++) { + if( gatindex[i]!=i ) { shuffledAtoms=1; break; } + } } else { - shuffledAtoms=1; + shuffledAtoms=1; } - if(dd){ - dd.Sum(shuffledAtoms); - for(unsigned i=0;i<gatindex.size();i++) dd.g2l[gatindex[i]]=i; + if(dd) { + dd.Sum(shuffledAtoms); + for(unsigned i=0; i<gatindex.size(); i++) dd.g2l[gatindex[i]]=i; } } -void Atoms::setAtomsContiguous(int start){ +void Atoms::setAtomsContiguous(int start) { ddStep=plumed.getStep(); - for(unsigned i=0;i<gatindex.size();i++) gatindex[i]=start+i; - for(unsigned i=0;i<dd.g2l.size();i++) dd.g2l[i]=-1; - if(dd) for(unsigned i=0;i<gatindex.size();i++) dd.g2l[gatindex[i]]=i; + for(unsigned i=0; i<gatindex.size(); i++) gatindex[i]=start+i; + for(unsigned i=0; i<dd.g2l.size(); i++) dd.g2l[i]=-1; + if(dd) for(unsigned i=0; i<gatindex.size(); i++) dd.g2l[gatindex[i]]=i; if(gatindex.size()<natoms) shuffledAtoms=1; } -void Atoms::setRealPrecision(int p){ +void Atoms::setRealPrecision(int p) { MDAtomsBase *x=MDAtomsBase::create(p); delete mdatoms; mdatoms=x; } -int Atoms::getRealPrecision()const{ +int Atoms::getRealPrecision()const { return mdatoms->getRealPrecision(); } -void Atoms::MD2double(const void*m,double&d)const{ +void Atoms::MD2double(const void*m,double&d)const { plumed_assert(mdatoms); mdatoms->MD2double(m,d); } -void Atoms::double2MD(const double&d,void*m)const{ +void Atoms::double2MD(const double&d,void*m)const { plumed_assert(mdatoms); mdatoms->double2MD(d,m); } -void Atoms::updateUnits(){ +void Atoms::updateUnits() { mdatoms->setUnits(units,MDUnits); } -void Atoms::setTimeStep(void*p){ +void Atoms::setTimeStep(void*p) { MD2double(p,timestep); } -double Atoms::getTimeStep()const{ +double Atoms::getTimeStep()const { return timestep/units.getTime()*MDUnits.getTime(); } -void Atoms::setKbT(void*p){ +void Atoms::setKbT(void*p) { MD2double(p,kbT); } -double Atoms::getKbT()const{ +double Atoms::getKbT()const { return kbT/units.getEnergy()*MDUnits.getEnergy(); } -void Atoms::createFullList(int*n){ +void Atoms::createFullList(int*n) { vector<AtomNumber> fullListTmp; - for(unsigned i=0;i<actions.size();i++) if(actions[i]->isActive()) - fullListTmp.insert(fullListTmp.end(),actions[i]->getUnique().begin(),actions[i]->getUnique().end()); + for(unsigned i=0; i<actions.size(); i++) if(actions[i]->isActive()) + fullListTmp.insert(fullListTmp.end(),actions[i]->getUnique().begin(),actions[i]->getUnique().end()); std::sort(fullListTmp.begin(),fullListTmp.end()); int nn=std::unique(fullListTmp.begin(),fullListTmp.end())-fullListTmp.begin(); fullList.resize(nn); - for(int i=0;i<nn;++i) fullList[i]=fullListTmp[i].index(); + for(int i=0; i<nn; ++i) fullList[i]=fullListTmp[i].index(); *n=nn; } -void Atoms::getFullList(int**x){ +void Atoms::getFullList(int**x) { if(!fullList.empty()) *x=&fullList[0]; else *x=NULL; } -void Atoms::clearFullList(){ +void Atoms::clearFullList() { fullList.resize(0); } -void Atoms::init(){ +void Atoms::init() { // Default: set domain decomposition to NO-decomposition, waiting for // further instruction - if(dd){ + if(dd) { setAtomsNlocal(natoms); setAtomsContiguous(0); } } -void Atoms::setDomainDecomposition(Communicator& comm){ +void Atoms::setDomainDecomposition(Communicator& comm) { dd.enable(comm); } -void Atoms::resizeVectors(unsigned n){ +void Atoms::resizeVectors(unsigned n) { positions.resize(n); forces.resize(n); masses.resize(n); charges.resize(n); } -AtomNumber Atoms::addVirtualAtom(ActionWithVirtualAtom*a){ +AtomNumber Atoms::addVirtualAtom(ActionWithVirtualAtom*a) { unsigned n=positions.size(); resizeVectors(n+1); virtualAtomsActions.push_back(a); return AtomNumber::index(n); } -void Atoms::removeVirtualAtom(ActionWithVirtualAtom*a){ +void Atoms::removeVirtualAtom(ActionWithVirtualAtom*a) { unsigned n=positions.size(); plumed_massert(a==virtualAtomsActions[virtualAtomsActions.size()-1],"virtual atoms should be destroyed in reverse creation order"); resizeVectors(n-1); virtualAtomsActions.pop_back(); } -void Atoms::insertGroup(const std::string&name,const std::vector<AtomNumber>&a){ +void Atoms::insertGroup(const std::string&name,const std::vector<AtomNumber>&a) { plumed_massert(groups.count(name)==0,"group named "+name+" already exists"); groups[name]=a; } -void Atoms::removeGroup(const std::string&name){ +void Atoms::removeGroup(const std::string&name) { plumed_massert(groups.count(name)==1,"cannot remove group named "+name); groups.erase(name); } -void Atoms::writeBinary(std::ostream&o)const{ +void Atoms::writeBinary(std::ostream&o)const { o.write(reinterpret_cast<const char*>(&positions[0][0]),natoms*3*sizeof(double)); o.write(reinterpret_cast<const char*>(&box(0,0)),9*sizeof(double)); o.write(reinterpret_cast<const char*>(&energy),sizeof(double)); } -void Atoms::readBinary(std::istream&i){ +void Atoms::readBinary(std::istream&i) { i.read(reinterpret_cast<char*>(&positions[0][0]),natoms*3*sizeof(double)); i.read(reinterpret_cast<char*>(&box(0,0)),9*sizeof(double)); i.read(reinterpret_cast<char*>(&energy),sizeof(double)); pbc.setBox(box); } -double Atoms::getKBoltzmann()const{ +double Atoms::getKBoltzmann()const { if(naturalUnits) return 1.0; else return kBoltzmann/units.getEnergy(); } -double Atoms::getMDKBoltzmann()const{ +double Atoms::getMDKBoltzmann()const { if(naturalUnits) return 1.0; else return kBoltzmann/MDUnits.getEnergy(); } -void Atoms::getLocalMasses(std::vector<double>& localMasses){ - localMasses.resize(gatindex.size()); - for(unsigned i=0; i<gatindex.size(); i++) localMasses[i] = masses[gatindex[i]]; +void Atoms::getLocalMasses(std::vector<double>& localMasses) { + localMasses.resize(gatindex.size()); + for(unsigned i=0; i<gatindex.size(); i++) localMasses[i] = masses[gatindex[i]]; } -void Atoms::getLocalPositions(std::vector<Vector>& localPositions){ +void Atoms::getLocalPositions(std::vector<Vector>& localPositions) { localPositions.resize(gatindex.size()); mdatoms->getLocalPositions(localPositions); } -void Atoms::getLocalForces(std::vector<Vector>& localForces){ +void Atoms::getLocalForces(std::vector<Vector>& localForces) { localForces.resize(gatindex.size()); for(unsigned i=0; i<gatindex.size(); i++) localForces[i] = forces[gatindex[i]]; } -void Atoms::getLocalMDForces(std::vector<Vector>& localForces){ +void Atoms::getLocalMDForces(std::vector<Vector>& localForces) { localForces.resize(gatindex.size()); for(unsigned i=0; i<gatindex.size(); i++) { localForces[i] = mdatoms->getMDforces(i); diff --git a/src/core/Atoms.h b/src/core/Atoms.h index 4e7ed103d..e9cccf399 100644 --- a/src/core/Atoms.h +++ b/src/core/Atoms.h @@ -32,7 +32,7 @@ #include <map> #include <string> -namespace PLMD{ +namespace PLMD { class MDAtomsBase; class PlumedMain; @@ -77,7 +77,7 @@ class Atoms void resizeVectors(unsigned); std::vector<int> fullList; - + MDAtomsBase* mdatoms; PlumedMain & plumed; @@ -114,15 +114,15 @@ class Atoms std::vector<Communicator::Request> mpi_request_positions; std::vector<Communicator::Request> mpi_request_index; - + std::vector<double> positionsToBeSent; std::vector<double> positionsToBeReceived; std::vector<int> indexToBeSent; std::vector<int> indexToBeReceived; - operator bool() const{return on;} + operator bool() const {return on;} DomainDecomposition(): on(false), async(false) - {} + {} void enable(Communicator& c); }; @@ -164,7 +164,7 @@ public: void getLocalMDForces(std::vector<Vector>&); const Tensor& getVirial()const; - void setCollectEnergy(bool b){ collectEnergy=b; } + void setCollectEnergy(bool b) { collectEnergy=b; } void setDomainDecomposition(Communicator&); void setAtomsGatindex(int*,bool); @@ -194,18 +194,18 @@ public: void add(const ActionAtomistic*); void remove(const ActionAtomistic*); - double getEnergy()const{plumed_assert(collectEnergy && energyHasBeenSet); return energy;} + double getEnergy()const {plumed_assert(collectEnergy && energyHasBeenSet); return energy;} - bool isEnergyNeeded()const{return collectEnergy;} + bool isEnergyNeeded()const {return collectEnergy;} - void setMDEnergyUnits(double d){MDUnits.setEnergy(d);} - void setMDLengthUnits(double d){MDUnits.setLength(d);} - void setMDTimeUnits(double d){MDUnits.setTime(d);} - void setMDChargeUnits(double d){MDUnits.setCharge(d);} - void setMDMassUnits(double d){MDUnits.setMass(d);} - const Units& getMDUnits(){return MDUnits;} - void setUnits(const Units&u){units=u;} - const Units& getUnits(){return units;} + void setMDEnergyUnits(double d) {MDUnits.setEnergy(d);} + void setMDLengthUnits(double d) {MDUnits.setLength(d);} + void setMDTimeUnits(double d) {MDUnits.setTime(d);} + void setMDChargeUnits(double d) {MDUnits.setCharge(d);} + void setMDMassUnits(double d) {MDUnits.setMass(d);} + const Units& getMDUnits() {return MDUnits;} + void setUnits(const Units&u) {units=u;} + const Units& getUnits() {return units;} void updateUnits(); AtomNumber addVirtualAtom(ActionWithVirtualAtom*); @@ -219,37 +219,37 @@ public: double getKBoltzmann()const; double getMDKBoltzmann()const; bool usingNaturalUnits()const; - void setNaturalUnits(bool n){naturalUnits=n;} - void setMDNaturalUnits(bool n){MDnaturalUnits=n;} + void setNaturalUnits(bool n) {naturalUnits=n;} + void setMDNaturalUnits(bool n) {MDnaturalUnits=n;} }; inline -const int & Atoms::getNatoms()const{ +const int & Atoms::getNatoms()const { return natoms; } inline -const long int& Atoms::getDdStep()const{ +const long int& Atoms::getDdStep()const { return ddStep; } inline -const std::vector<int>& Atoms::getGatindex()const{ +const std::vector<int>& Atoms::getGatindex()const { return gatindex; } inline -const Pbc& Atoms::getPbc()const{ +const Pbc& Atoms::getPbc()const { return pbc; } inline -bool Atoms::isVirtualAtom(AtomNumber i)const{ +bool Atoms::isVirtualAtom(AtomNumber i)const { return i.index()>=(unsigned) getNatoms(); } inline -ActionWithVirtualAtom* Atoms::getVirtualAtomsAction(AtomNumber i)const{ +ActionWithVirtualAtom* Atoms::getVirtualAtomsAction(AtomNumber i)const { return virtualAtomsActions[i.index()-getNatoms()]; } @@ -269,7 +269,7 @@ bool Atoms::boxWasSet() const { } inline -const Tensor& Atoms::getVirial()const{ +const Tensor& Atoms::getVirial()const { return virial; } diff --git a/src/core/CLTool.cpp b/src/core/CLTool.cpp index 527e5b6cb..c7441d41e 100644 --- a/src/core/CLTool.cpp +++ b/src/core/CLTool.cpp @@ -21,148 +21,148 @@ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ #include "CLTool.h" -namespace PLMD{ +namespace PLMD { Keywords CLToolOptions::emptyKeys; -CLToolOptions::CLToolOptions(const std::string &name): -line(1,name), -keys(emptyKeys) +CLToolOptions::CLToolOptions(const std::string &name): + line(1,name), + keys(emptyKeys) { } CLToolOptions::CLToolOptions(const CLToolOptions& co, const Keywords& k): -line(co.line), -keys(k) + line(co.line), + keys(k) { } -void CLTool::registerKeywords( Keywords& keys ){ +void CLTool::registerKeywords( Keywords& keys ) { keys.addFlag("--help/-h",false,"print this help"); } -CLTool::CLTool(const CLToolOptions& co ): -name(co.line[0]), -keywords(co.keys), -inputdata(unset) +CLTool::CLTool(const CLToolOptions& co ): + name(co.line[0]), + keywords(co.keys), + inputdata(unset) { } -void CLTool::parseFlag( const std::string&key, bool&t ){ +void CLTool::parseFlag( const std::string&key, bool&t ) { plumed_massert(keywords.exists(key),"keyword " + key + " has not been registered"); plumed_massert(keywords.style(key,"flag"),"keyword " + key + " has not been registered as a flag"); - plumed_assert(inputData.count(key)>0); + plumed_assert(inputData.count(key)>0); if( inputData[key]=="true") t=true; else if( inputData[key]=="false") t=false; else plumed_error(); } -bool CLTool::readInput( int argc, char**argv, FILE* in, FILE*out ){ +bool CLTool::readInput( int argc, char**argv, FILE* in, FILE*out ) { plumed_massert( inputdata!=unset,"You have not specified where your tool reads its input. " - "If it is from the command line (like driver) add inputdata=commandline to the " - "tools constructor. If it reads everything from an input file (like simplemd) " - "add inputdata=ifile to the tools constructor"); + "If it is from the command line (like driver) add inputdata=commandline to the " + "tools constructor. If it reads everything from an input file (like simplemd) " + "add inputdata=ifile to the tools constructor"); if(inputdata==commandline) return readCommandLineArgs( argc, argv, out ); if(inputdata==ifile) return readInputFile( argc, argv, in, out ); return true; } -bool CLTool::readCommandLineArgs( int argc, char**argv, FILE*out ){ +bool CLTool::readCommandLineArgs( int argc, char**argv, FILE*out ) { plumed_assert(inputdata==commandline); std::string prefix(""), a(""), thiskey; // Set all flags to default false - for(unsigned k=0;k<keywords.size();++k){ - thiskey=keywords.get(k); - if( keywords.style(thiskey,"flag") ) inputData.insert(std::pair<std::string,std::string>(thiskey,"false")); + for(unsigned k=0; k<keywords.size(); ++k) { + thiskey=keywords.get(k); + if( keywords.style(thiskey,"flag") ) inputData.insert(std::pair<std::string,std::string>(thiskey,"false")); } // Read command line arguments bool printhelp=false; - for(int i=1;i<argc;i++){ - a=prefix+argv[i]; - if(a.length()==0) continue; - if(a=="-h" || a=="--help"){ - printhelp=true; - } else { - bool found=false; - for(unsigned k=0;k<keywords.size();++k){ - thiskey=keywords.get(k); - if( keywords.style(thiskey,"flag") ){ - if( a==thiskey ){ found=true; inputData[thiskey]="true"; } - } else { - if( a==thiskey ){ - prefix=thiskey+"="; found=true; - inputData.insert(std::pair<std::string,std::string>(thiskey,"")); - } else if(Tools::startWith(a,thiskey+"=")){ - a.erase(0,a.find("=")+1); prefix=""; found=true; - if(inputData.count(thiskey)==0){ - inputData.insert(std::pair<std::string,std::string>(thiskey,a)); - } else { - inputData[thiskey]=a; - } - } - } - } - if(!found){ - fprintf(stderr,"ERROR in input for command line tool %s : %s option is unknown \n\n", name.c_str(), a.c_str() ); - fprintf(out,"Usage: %s < inputFile \n", name.c_str() ); - fprintf(out,"inputFile should contain one directive per line. The directives should come from amongst the following\n\n"); - keywords.print( out ); - printhelp=true; - } + for(int i=1; i<argc; i++) { + a=prefix+argv[i]; + if(a.length()==0) continue; + if(a=="-h" || a=="--help") { + printhelp=true; + } else { + bool found=false; + for(unsigned k=0; k<keywords.size(); ++k) { + thiskey=keywords.get(k); + if( keywords.style(thiskey,"flag") ) { + if( a==thiskey ) { found=true; inputData[thiskey]="true"; } + } else { + if( a==thiskey ) { + prefix=thiskey+"="; found=true; + inputData.insert(std::pair<std::string,std::string>(thiskey,"")); + } else if(Tools::startWith(a,thiskey+"=")) { + a.erase(0,a.find("=")+1); prefix=""; found=true; + if(inputData.count(thiskey)==0) { + inputData.insert(std::pair<std::string,std::string>(thiskey,a)); + } else { + inputData[thiskey]=a; + } + } + } + } + if(!found) { + fprintf(stderr,"ERROR in input for command line tool %s : %s option is unknown \n\n", name.c_str(), a.c_str() ); + fprintf(out,"Usage: %s < inputFile \n", name.c_str() ); + fprintf(out,"inputFile should contain one directive per line. The directives should come from amongst the following\n\n"); + keywords.print( out ); + printhelp=true; } - if(printhelp) break; + } + if(printhelp) break; } if(!printhelp) setRemainingToDefault(out); - if(printhelp){ - fprintf(out,"Usage: %s [options] \n\n", name.c_str() ); - keywords.print( out ); + if(printhelp) { + fprintf(out,"Usage: %s [options] \n\n", name.c_str() ); + keywords.print( out ); } return !printhelp; } -void CLTool::setRemainingToDefault(FILE* out){ +void CLTool::setRemainingToDefault(FILE* out) { std::string def, thiskey; - for(unsigned k=0;k<keywords.size();++k){ - thiskey=keywords.get(k); - if( keywords.style(thiskey,"compulsory") ){ - if( inputData.count(thiskey)==0 ){ - if( keywords.getDefaultValue(thiskey,def) ){ - plumed_assert( def.length()>0 ); - inputData.insert(std::pair<std::string,std::string>(thiskey,def)); - } else { - fprintf(out,"ERROR : argument %s is compulsory. Use --help option for help\n",thiskey.c_str() ); - plumed_error(); - } - } + for(unsigned k=0; k<keywords.size(); ++k) { + thiskey=keywords.get(k); + if( keywords.style(thiskey,"compulsory") ) { + if( inputData.count(thiskey)==0 ) { + if( keywords.getDefaultValue(thiskey,def) ) { + plumed_assert( def.length()>0 ); + inputData.insert(std::pair<std::string,std::string>(thiskey,def)); + } else { + fprintf(out,"ERROR : argument %s is compulsory. Use --help option for help\n",thiskey.c_str() ); + plumed_error(); + } } + } } } -bool CLTool::readInputFile( int argc, char**argv, FILE* in, FILE*out ){ +bool CLTool::readInputFile( int argc, char**argv, FILE* in, FILE*out ) { plumed_assert(inputdata==ifile); // Check if use is just asking for help std::string a; - for(int i=1;i<argc;i++){ - a=argv[i]; - if(a.length()==0) continue; - if(a=="-h" || a=="--help"){ - fprintf(out,"Usage: %s < inputFile \n", name.c_str() ); - fprintf(out,"inputFile should contain one directive per line. The directives should come from amongst the following\n\n"); - keywords.print( out ); - return false; - } + for(int i=1; i<argc; i++) { + a=argv[i]; + if(a.length()==0) continue; + if(a=="-h" || a=="--help") { + fprintf(out,"Usage: %s < inputFile \n", name.c_str() ); + fprintf(out,"inputFile should contain one directive per line. The directives should come from amongst the following\n\n"); + keywords.print( out ); + return false; + } } FILE* mystdin=in; - if(argc==2){ + if(argc==2) { mystdin=fopen(argv[1],"r"); - if(!mystdin){ + if(!mystdin) { fprintf(stderr,"ERROR: cannot open file %s\n\n",argv[1]); fprintf(out,"Usage: %s < inputFile \n", name.c_str() ); fprintf(out,"inputFile should contain one directive per line. The directives should come from amongst the following\n\n"); @@ -174,30 +174,30 @@ bool CLTool::readInputFile( int argc, char**argv, FILE* in, FILE*out ){ plumed_assert(mystdin); char buffer[256]; std::string line; line.resize(256); - while(fgets(buffer,256,mystdin)){ - line=buffer; - for(unsigned i=0;i<line.length();++i) if(line[i]=='#' || line[i]=='\n') line.erase(i); - Tools::stripLeadingAndTrailingBlanks( line ); - if(line.length()==0) continue; - sscanf(line.c_str(),"%255s",buffer); - std::string keyword=buffer; bool found=false; - for(unsigned i=0;i<keywords.size();++i){ - std::string thiskey=keywords.get(i); - if(thiskey==keyword){ - found=true; - std::size_t keypos=line.find_first_of(keyword)+keyword.length(); - inputData.insert(std::pair<std::string,std::string>(thiskey,line.substr(keypos))); - Tools::stripLeadingAndTrailingBlanks( inputData[thiskey] ); - } - } - if(!found){ - fprintf(stderr,"ERROR in input for command line tool %s : unknown keyword %s found in input file\n\n",name.c_str(),keyword.c_str()); - fprintf(out,"Usage: %s < inputFile \n", name.c_str() ); - fprintf(out,"inputFile should contain one directive per line. The directives should come from amongst the following\n\n"); - keywords.print( out ); - fclose(mystdin); - return false; - } + while(fgets(buffer,256,mystdin)) { + line=buffer; + for(unsigned i=0; i<line.length(); ++i) if(line[i]=='#' || line[i]=='\n') line.erase(i); + Tools::stripLeadingAndTrailingBlanks( line ); + if(line.length()==0) continue; + sscanf(line.c_str(),"%255s",buffer); + std::string keyword=buffer; bool found=false; + for(unsigned i=0; i<keywords.size(); ++i) { + std::string thiskey=keywords.get(i); + if(thiskey==keyword) { + found=true; + std::size_t keypos=line.find_first_of(keyword)+keyword.length(); + inputData.insert(std::pair<std::string,std::string>(thiskey,line.substr(keypos))); + Tools::stripLeadingAndTrailingBlanks( inputData[thiskey] ); + } + } + if(!found) { + fprintf(stderr,"ERROR in input for command line tool %s : unknown keyword %s found in input file\n\n",name.c_str(),keyword.c_str()); + fprintf(out,"Usage: %s < inputFile \n", name.c_str() ); + fprintf(out,"inputFile should contain one directive per line. The directives should come from amongst the following\n\n"); + keywords.print( out ); + fclose(mystdin); + return false; + } } if(argc==2) fclose(mystdin); @@ -205,9 +205,9 @@ bool CLTool::readInputFile( int argc, char**argv, FILE* in, FILE*out ){ return true; } -void CLTool::error( const std::string& msg ){ +void CLTool::error( const std::string& msg ) { fprintf(stderr,"ERROR : in input for command line tool %s : %s\n",name.c_str(),msg.c_str()); - plumed_error(); + plumed_error(); } } diff --git a/src/core/CLTool.h b/src/core/CLTool.h index 9385c93d8..c9ab30778 100644 --- a/src/core/CLTool.h +++ b/src/core/CLTool.h @@ -28,11 +28,11 @@ #include "tools/Tools.h" #include "tools/Keywords.h" -namespace PLMD{ +namespace PLMD { class Communicator; -class CLToolOptions{ +class CLToolOptions { friend class CLTool; friend class CLToolRegister; private: @@ -67,92 +67,92 @@ private: void setRemainingToDefault(FILE* out); public: /// Set the input data: - void setInputData(const std::map<std::string,std::string>&inputData){ + void setInputData(const std::map<std::string,std::string>&inputData) { this->inputData=inputData; } - const std::map<std::string,std::string>&getInputData(){ + const std::map<std::string,std::string>&getInputData() { return this->inputData; } protected: -/// Get the value of one of the command line arguments +/// Get the value of one of the command line arguments template<class T> bool parse(const std::string&key,T&t); /// Find out whether one of the command line flags is present or not - void parseFlag(const std::string&key,bool&t); + void parseFlag(const std::string&key,bool&t); /// Crash the command line tool with an error void error(const std::string& msg); template<class T> - bool parseVector(const std::string&key,std::vector<T>&t); + bool parseVector(const std::string&key,std::vector<T>&t); public: /// How is the input specified on the command line or in an input file enum {unset,commandline,ifile} inputdata; -/// Create the help keywords +/// Create the help keywords static void registerKeywords( Keywords& keys ); - explicit CLTool(const CLToolOptions& co ); + explicit CLTool(const CLToolOptions& co ); /// Read the arguments from the command line bool readInput( int argc, char**argv, FILE* in, FILE*out ); /// virtual function mapping to the specific main for each tool virtual int main( FILE* in, FILE*out, Communicator&pc )=0; /// virtual function returning a one-line descriptor for the tool - virtual std::string description()const{return "(no description available)";} + virtual std::string description()const {return "(no description available)";} /// virtual destructor to allow inheritance - virtual ~CLTool(){} + virtual ~CLTool() {} }; template<class T> -bool CLTool::parse(const std::string&key,T&t){ +bool CLTool::parse(const std::string&key,T&t) { plumed_massert(keywords.exists(key),"keyword " + key + " has not been registered"); - if(keywords.style(key,"compulsory") ){ - if(inputData.count(key)==0) error("missing data for keyword " + key); - bool check=Tools::convert(inputData[key],t); - if(!check) error("data input for keyword " + key + " has wrong type"); - return true; + if(keywords.style(key,"compulsory") ) { + if(inputData.count(key)==0) error("missing data for keyword " + key); + bool check=Tools::convert(inputData[key],t); + if(!check) error("data input for keyword " + key + " has wrong type"); + return true; } - if( inputData.count(key)==0 ) return false; + if( inputData.count(key)==0 ) return false; Tools::convert(inputData[key],t); return true; } -// very limited support and check: take more from core/Action.h parseVector +// very limited support and check: take more from core/Action.h parseVector template<class T> -bool CLTool::parseVector(const std::string&key,std::vector<T>&t){ +bool CLTool::parseVector(const std::string&key,std::vector<T>&t) { // Check keyword has been registered plumed_massert(keywords.exists(key), "keyword " + key + " has not been registered"); // initial size - unsigned size=t.size(); + unsigned size=t.size(); bool skipcheck=false; - if(size==0) skipcheck=true; // if the vector in input has size zero, skip the check if size of input vector is the same of argument read + if(size==0) skipcheck=true; // if the vector in input has size zero, skip the check if size of input vector is the same of argument read // check if there is some value plumed_massert(inputData[key]!="false","compulsory keyword "+std::string(key)+"has no data"); std::vector<std::string> words=Tools::getWords(inputData[key],"\t\n ,"); - t.resize(0); + t.resize(0); if(words.size()==0)return false; - for(unsigned i=0;i<words.size();++i){ + for(unsigned i=0; i<words.size(); ++i) { T v; Tools::convert(words[i],v); t.push_back(v); } // check the size if( !skipcheck && t.size()!=size ) { - plumed_merror("vector read in for keyword "+key+" has wrong size" ); + plumed_merror("vector read in for keyword "+key+" has wrong size" ); } std::string def; T val; - if ( keywords.style(key,"compulsory") && t.size()==0 ){ - if( keywords.getDefaultValue(key,def) ){ - if( def.length()==0 || !Tools::convert(def,val) ){ - plumed_merror("ERROR in keyword "+key+ " has weird default value" ); - } else { - for(unsigned i=0;i<t.size();++i) t[i]=val; - } - } else { - plumed_merror("keyword " + key + " is compulsory for this action"); - } - } - return true; + if ( keywords.style(key,"compulsory") && t.size()==0 ) { + if( keywords.getDefaultValue(key,def) ) { + if( def.length()==0 || !Tools::convert(def,val) ) { + plumed_merror("ERROR in keyword "+key+ " has weird default value" ); + } else { + for(unsigned i=0; i<t.size(); ++i) t[i]=val; + } + } else { + plumed_merror("keyword " + key + " is compulsory for this action"); + } + } + return true; } diff --git a/src/core/CLToolMain.cpp b/src/core/CLToolMain.cpp index f60bca99d..5c3598b0e 100644 --- a/src/core/CLToolMain.cpp +++ b/src/core/CLToolMain.cpp @@ -34,61 +34,61 @@ #include <algorithm> using namespace std; -namespace PLMD{ +namespace PLMD { CLToolMain::CLToolMain(): -argc(0), -in(stdin), -out(stdout), -comm(*new Communicator) + argc(0), + in(stdin), + out(stdout), + comm(*new Communicator) { } -CLToolMain::~CLToolMain(){ +CLToolMain::~CLToolMain() { delete &comm; } #define CHECK_NULL(val,word) plumed_massert(val,"NULL pointer received in cmd(\"CLTool " + word + "\")"); -void CLToolMain::cmd(const std::string& word,void*val){ - if(false){ - } else if(word=="setArgc"){ - CHECK_NULL(val,word); - argc=*static_cast<int*>(val); - } else if(word=="setArgv"){ - CHECK_NULL(val,word); - char**v=static_cast<char**>(val); - for(int i=0;i<argc;++i) argv.push_back(string(v[i])); - } else if(word=="setArgvLine"){ - CHECK_NULL(val,word); - const char*v=static_cast<char*>(val); - argv=Tools::getWords(v); - } else if(word=="setIn"){ - CHECK_NULL(val,word); - in=static_cast<FILE*>(val); - } else if(word=="setOut"){ - CHECK_NULL(val,word); - out=static_cast<FILE*>(val); - } else if(word=="setMPIComm"){ - comm.Set_comm(val); - } else if(word=="setMPIFComm"){ - comm.Set_fcomm(val); - } else if(word=="run"){ - CHECK_NULL(val,word); - argc=argv.size(); - int n=0; for(int i=0;i<argc;++i) n+=argv[i].length()+1; - std::vector<char> args(n); - std::vector<char*> v(argc); - char* ptr=&args[0]; - for(int i=0;i<argc;++i){ - v[i]=ptr; - for(unsigned c=0;c<argv[i].length();++c){ - *ptr=argv[i][c]; ptr++; - } - *ptr=0; ptr++; - } - int ret=run(argc,&v[0],in,out,comm); - *static_cast<int*>(val)=ret; +void CLToolMain::cmd(const std::string& word,void*val) { + if(false) { + } else if(word=="setArgc") { + CHECK_NULL(val,word); + argc=*static_cast<int*>(val); + } else if(word=="setArgv") { + CHECK_NULL(val,word); + char**v=static_cast<char**>(val); + for(int i=0; i<argc; ++i) argv.push_back(string(v[i])); + } else if(word=="setArgvLine") { + CHECK_NULL(val,word); + const char*v=static_cast<char*>(val); + argv=Tools::getWords(v); + } else if(word=="setIn") { + CHECK_NULL(val,word); + in=static_cast<FILE*>(val); + } else if(word=="setOut") { + CHECK_NULL(val,word); + out=static_cast<FILE*>(val); + } else if(word=="setMPIComm") { + comm.Set_comm(val); + } else if(word=="setMPIFComm") { + comm.Set_fcomm(val); + } else if(word=="run") { + CHECK_NULL(val,word); + argc=argv.size(); + int n=0; for(int i=0; i<argc; ++i) n+=argv[i].length()+1; + std::vector<char> args(n); + std::vector<char*> v(argc); + char* ptr=&args[0]; + for(int i=0; i<argc; ++i) { + v[i]=ptr; + for(unsigned c=0; c<argv[i].length(); ++c) { + *ptr=argv[i][c]; ptr++; + } + *ptr=0; ptr++; + } + int ret=run(argc,&v[0],in,out,comm); + *static_cast<int*>(val)=ret; } else { plumed_merror("cannot interpret cmd(\"CLTool " + word + "\"). check plumed developers manual to see the available commands."); } @@ -99,7 +99,7 @@ This is the entry point to the command line tools included in the plumed library. */ -int CLToolMain::run(int argc, char **argv,FILE*in,FILE*out,Communicator& pc){ +int CLToolMain::run(int argc, char **argv,FILE*in,FILE*out,Communicator& pc) { int i; bool printhelp=false; @@ -112,55 +112,55 @@ int CLToolMain::run(int argc, char **argv,FILE*in,FILE*out,Communicator& pc){ // Start parsing options string prefix(""); string a(""); - for(i=1;i<argc;i++){ + for(i=1; i<argc; i++) { a=prefix+argv[i]; if(a.length()==0) continue; - if(a=="help" || a=="-h" || a=="--help"){ + if(a=="help" || a=="-h" || a=="--help") { printhelp=true; break; - } else if(a=="--has-mpi"){ + } else if(a=="--has-mpi") { if(Communicator::initialized()) return 0; else return 1; - } else if(a=="--has-matheval"){ + } else if(a=="--has-matheval") { return (config::hasMatheval()?0:1); - } else if(a=="--has-cregex"){ + } else if(a=="--has-cregex") { return (config::hasCregex()?0:1); - } else if(a=="--has-dlopen"){ + } else if(a=="--has-dlopen") { return (config::hasDlopen()?0:1); - } else if(a=="--has-molfile"){ + } else if(a=="--has-molfile") { return (config::hasMolfile()?0:1); - } else if(a=="--has-external-molfile"){ + } else if(a=="--has-external-molfile") { return (config::hasExternalMolfile()?0:1); - } else if(a=="--has-zlib"){ + } else if(a=="--has-zlib") { return (config::hasZlib()?0:1); - } else if(a=="--has-xdrfile"){ + } else if(a=="--has-xdrfile") { return (config::hasXdrfile()?0:1); - } else if(a=="--is-installed"){ + } else if(a=="--is-installed") { return (config::isInstalled()?0:1); - } else if(a=="--no-mpi"){ + } else if(a=="--no-mpi") { // this is ignored, as it is parsed in main - if(i>1){ + if(i>1) { fprintf(stderr,"--no-mpi option can only be used as the first option"); return 1; } - } else if(a=="--mpi"){ + } else if(a=="--mpi") { // this is ignored, as it is parsed in main - if(i>1){ + if(i>1) { fprintf(stderr,"--mpi option can only be used as the first option"); return 1; } - } else if(a=="--standalone-executable"){ + } else if(a=="--standalone-executable") { standalone_executable=true; - } else if(Tools::startWith(a,"--load=")){ + } else if(Tools::startWith(a,"--load=")) { a.erase(0,a.find("=")+1); prefix=""; void *p=dlloader.load(a); - if(!p){ + if(!p) { fprintf(stderr,"ERROR: cannot load library %s\n",a.c_str()); fprintf(stderr,"ERROR: %s\n",dlloader.error().c_str()); return 1; } - } else if(a=="--load"){ + } else if(a=="--load") { prefix="--load="; } else if(a[0]=='-') { string msg="ERROR: Unknown option " +a; @@ -170,11 +170,11 @@ int CLToolMain::run(int argc, char **argv,FILE*in,FILE*out,Communicator& pc){ } // Check if plumedRoot/patches/ directory exists (as a further check) - if(!standalone_executable){ + if(!standalone_executable) { vector<string> files=Tools::ls(root); if(find(files.begin(),files.end(),"patches")==files.end()) { string msg= - "WARNING: I cannot find "+root+"/patches/ directory. Set PLUMED_ROOT or reinstall PLUMED\n\n"; + "WARNING: I cannot find "+root+"/patches/ directory. Set PLUMED_ROOT or reinstall PLUMED\n\n"; fprintf(stderr,"%s",msg.c_str()); } } @@ -186,36 +186,36 @@ int CLToolMain::run(int argc, char **argv,FILE*in,FILE*out,Communicator& pc){ if(!standalone_executable) { vector<string> tmp; tmp=Tools::ls(string(root+"/scripts")); - for(unsigned j=0;j<tmp.size();++j){ + for(unsigned j=0; j<tmp.size(); ++j) { size_t ff=tmp[j].find(".sh"); if(ff==string::npos) tmp[j].erase(); else tmp[j].erase(ff); } - for(unsigned j=0;j<tmp.size();++j) if(tmp[j].length()>0) availableShell.push_back(tmp[j]); + for(unsigned j=0; j<tmp.size(); ++j) if(tmp[j].length()>0) availableShell.push_back(tmp[j]); } - if(printhelp){ + if(printhelp) { string msg= - "Usage: plumed [options] [command] [command options]\n" - " plumed [command] -h|--help: to print help for a specific command\n" - "Options:\n" - " [help|-h|--help] : to print this help\n" - " [--is-installed] : fails if plumed is not installed\n" - " [--has-mpi] : fails if plumed is running without MPI\n" - " [--has-matheval] : fails if plumed is compiled without matheval\n" - " [--has-dlopen] : fails if plumed is compiled without dlopen\n" - " [--load LIB] : loads a shared object (typically a plugin library)\n" - " [--standalone-executable] : tells plumed not to look for commands implemented as scripts\n" - "Commands:\n"; + "Usage: plumed [options] [command] [command options]\n" + " plumed [command] -h|--help: to print help for a specific command\n" + "Options:\n" + " [help|-h|--help] : to print this help\n" + " [--is-installed] : fails if plumed is not installed\n" + " [--has-mpi] : fails if plumed is running without MPI\n" + " [--has-matheval] : fails if plumed is compiled without matheval\n" + " [--has-dlopen] : fails if plumed is compiled without dlopen\n" + " [--load LIB] : loads a shared object (typically a plugin library)\n" + " [--standalone-executable] : tells plumed not to look for commands implemented as scripts\n" + "Commands:\n"; fprintf(out,"%s",msg.c_str()); - for(unsigned j=0;j<availableCxx.size();++j){ + for(unsigned j=0; j<availableCxx.size(); ++j) { CLTool *cl=cltoolRegister().create(CLToolOptions(availableCxx[j])); plumed_assert(cl); string manual=availableCxx[j]+" : "+cl->description(); delete cl; fprintf(out," plumed %s\n", manual.c_str()); } - for(unsigned j=0;j<availableShell.size();++j){ + for(unsigned j=0; j<availableShell.size(); ++j) { string cmd=config::getEnvCommand()+" \""+root+"/scripts/"+availableShell[j]+".sh\" --description"; FILE *fp=popen(cmd.c_str(),"r"); string line,manual; @@ -234,21 +234,21 @@ int CLToolMain::run(int argc, char **argv,FILE*in,FILE*out,Communicator& pc){ // this is the command to be executed: string command(argv[i]); - if(find(availableCxx.begin(),availableCxx.end(),command)!=availableCxx.end()){ + if(find(availableCxx.begin(),availableCxx.end(),command)!=availableCxx.end()) { CLTool *cl=cltoolRegister().create(CLToolOptions(command)); - plumed_assert(cl); + plumed_assert(cl); // Read the command line options (returns false if we are just printing help) - if( !cl->readInput( argc-i,&argv[i],in,out ) ){ delete cl; return 0; } + if( !cl->readInput( argc-i,&argv[i],in,out ) ) { delete cl; return 0; } int ret=cl->main(in,out,pc); delete cl; return ret; } - if(find(availableShell.begin(),availableShell.end(),command)!=availableShell.end()){ + if(find(availableShell.begin(),availableShell.end(),command)!=availableShell.end()) { plumed_massert(in==stdin,"shell tools can only work on stdin"); plumed_massert(out==stdout,"shell tools can only work on stdin"); string cmd=config::getEnvCommand()+" \""+root+"/scripts/"+command+".sh\""; - for(int j=i+1;j<argc;j++) cmd+=string(" ")+argv[j]; + for(int j=i+1; j<argc; j++) cmd+=string(" ")+argv[j]; int r=system(cmd.c_str()); // this is necessary since system seems to return numbers which are multiple // of 256. this would make the interpretation by the shell wrong diff --git a/src/core/CLToolMain.h b/src/core/CLToolMain.h index 48b317cff..a8cdb42e2 100644 --- a/src/core/CLToolMain.h +++ b/src/core/CLToolMain.h @@ -27,7 +27,7 @@ #include "WithCmd.h" -namespace PLMD{ +namespace PLMD { class Communicator; @@ -37,7 +37,7 @@ Class providing cmd() access to command line tools. This class provides an interface using the "cmd()" syntax to all the command-line tools. It is only accessed via the cmd() function, which can -be used to set the arguments, communicators and IO descriptors and +be used to set the arguments, communicators and IO descriptors and to run the tool. It can run all the tools registered via the PLUMED_REGISTER_CLTOOL macro, or the scripts which are located in PLUMED_ROOT/scripts. @@ -75,7 +75,7 @@ See the file \ref main.cpp for a similar example. */ class CLToolMain: -public WithCmd + public WithCmd { /// arguments for command-line mode: int argc; @@ -88,9 +88,9 @@ public WithCmd public: CLToolMain(); ~CLToolMain(); -/** -Send messages to the CLToolMain. -*/ + /** + Send messages to the CLToolMain. + */ void cmd(const std::string& key,void*val=NULL); }; diff --git a/src/core/CLToolRegister.cpp b/src/core/CLToolRegister.cpp index e5fdab5ef..ff1bbe829 100644 --- a/src/core/CLToolRegister.cpp +++ b/src/core/CLToolRegister.cpp @@ -27,81 +27,81 @@ using namespace std; -namespace PLMD{ +namespace PLMD { -CLToolRegister::~CLToolRegister(){ - if(m.size()>0){ +CLToolRegister::~CLToolRegister() { + if(m.size()>0) { string names=""; for(const auto & p : m) names+=p.first+" "; std::cerr<<"WARNING: CLTools "+ names +" has not been properly unregistered. This might lead to memory leak!!\n"; } } -CLToolRegister& cltoolRegister(){ +CLToolRegister& cltoolRegister() { static CLToolRegister ans; return ans; } -void CLToolRegister::remove(creator_pointer f){ - for(auto p=m.begin();p!=m.end();++p){ - if((*p).second==f){ +void CLToolRegister::remove(creator_pointer f) { + for(auto p=m.begin(); p!=m.end(); ++p) { + if((*p).second==f) { m.erase(p); break; } } } -void CLToolRegister::add(string key,creator_pointer f,keywords_pointer kf){ - if(m.count(key)){ +void CLToolRegister::add(string key,creator_pointer f,keywords_pointer kf) { + if(m.count(key)) { m.erase(key); disabled.insert(key); - }else{ + } else { m.insert(pair<string,creator_pointer>(key,f)); Keywords keys; kf(keys); mk.insert(pair<string,Keywords>(key,keys)); }; } -bool CLToolRegister::check(string key){ +bool CLToolRegister::check(string key) { if(m.count(key)>0) return true; return false; } -CLTool* CLToolRegister::create(const CLToolOptions&ao){ +CLTool* CLToolRegister::create(const CLToolOptions&ao) { if(ao.line.size()<1)return NULL; CLTool* cltool; - if(check(ao.line[0])){ - CLToolOptions nao( ao,mk[ao.line[0]] ); - cltool=m[ao.line[0]](nao); + if(check(ao.line[0])) { + CLToolOptions nao( ao,mk[ao.line[0]] ); + cltool=m[ao.line[0]](nao); } else cltool=NULL; return cltool; } -std::ostream & operator<<(std::ostream &log,const CLToolRegister&ar){ +std::ostream & operator<<(std::ostream &log,const CLToolRegister&ar) { vector<string> s(ar.list()); - for(unsigned i=0;i<s.size();i++) log<<" "<<s[i]<<"\n"; - if(!ar.disabled.empty()){ + for(unsigned i=0; i<s.size(); i++) log<<" "<<s[i]<<"\n"; + if(!ar.disabled.empty()) { s.assign(ar.disabled.size(),""); copy(ar.disabled.begin(),ar.disabled.end(),s.begin()); sort(s.begin(),s.end()); log<<"+++++++ WARNING +++++++\n"; log<<"The following keywords have been registered more than once and will be disabled:\n"; - for(unsigned i=0;i<s.size();i++) log<<" - "<<s[i]<<"\n"; + for(unsigned i=0; i<s.size(); i++) log<<" - "<<s[i]<<"\n"; log<<"+++++++ END WARNING +++++++\n"; }; return log; } -bool CLToolRegister::printManual( const std::string& cltool ){ - if ( check(cltool) ){ - mk[cltool].print_html(); - return true; +bool CLToolRegister::printManual( const std::string& cltool ) { + if ( check(cltool) ) { + mk[cltool].print_html(); + return true; } else { - return false; + return false; } } -vector<string> CLToolRegister::list()const{ +vector<string> CLToolRegister::list()const { vector<string> s; for(const auto & it : m) s.push_back(it.first); sort(s.begin(),s.end()); diff --git a/src/core/CLToolRegister.h b/src/core/CLToolRegister.h index 1d91bfe14..f7b14a561 100644 --- a/src/core/CLToolRegister.h +++ b/src/core/CLToolRegister.h @@ -29,13 +29,13 @@ #include <iosfwd> #include "tools/Keywords.h" -namespace PLMD{ +namespace PLMD { class CLTool; class CLToolOptions; /// Same as ActionRegister, but for CLTools -class CLToolRegister{ +class CLToolRegister { /// Write on a stream the list of registered directives friend std::ostream &operator<<(std::ostream &,const CLToolRegister&); /// Pointer to a function which, given the options, create an CLTool @@ -64,7 +64,7 @@ public: /// Returns a list of the allowed CLTools std::vector<std::string> list()const; /// Print out the instructions for using the tool in html ready for input into the manual - bool printManual(const std::string& cltool); + bool printManual(const std::string& cltool); }; /// Function returning a reference to the CLToolRegister. diff --git a/src/core/Colvar.cpp b/src/core/Colvar.cpp index bdd6b048e..239afdc8d 100644 --- a/src/core/Colvar.cpp +++ b/src/core/Colvar.cpp @@ -25,32 +25,32 @@ #include <string> using namespace std; -namespace PLMD{ +namespace PLMD { Colvar::Colvar(const ActionOptions&ao): -Action(ao), -ActionAtomistic(ao), -ActionWithValue(ao), -isEnergy(false) + Action(ao), + ActionAtomistic(ao), + ActionWithValue(ao), + isEnergy(false) { } -void Colvar::registerKeywords( Keywords& keys ){ +void Colvar::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionWithValue::registerKeywords( keys ); ActionAtomistic::registerKeywords( keys ); keys.addFlag("NOPBC",false,"ignore the periodic boundary conditions when calculating distances"); -} +} -void Colvar::requestAtoms(const vector<AtomNumber> & a){ +void Colvar::requestAtoms(const vector<AtomNumber> & a) { plumed_massert(!isEnergy,"request atoms should not be called if this is energy"); // Tell actionAtomistic what atoms we are getting ActionAtomistic::requestAtoms(a); // Resize the derivatives of all atoms - for(int i=0;i<getNumberOfComponents();++i) getPntrToComponent(i)->resizeDerivatives(3*a.size()+9); + for(int i=0; i<getNumberOfComponents(); ++i) getPntrToComponent(i)->resizeDerivatives(3*a.size()+9); } -void Colvar::apply(){ +void Colvar::apply() { vector<Vector>& f(modifyForces()); Tensor& v(modifyVirial()); const unsigned nat=getNumberOfAtoms(); @@ -67,16 +67,16 @@ void Colvar::apply(){ unsigned nt=OpenMP::getNumThreads(); if(nt>ncp/(2.*stride)) nt=1; - if(!isEnergy){ - #pragma omp parallel num_threads(nt) + if(!isEnergy) { + #pragma omp parallel num_threads(nt) { vector<Vector> omp_f(fsz); Tensor omp_v; vector<double> forces(3*nat+9); - #pragma omp for - for(unsigned i=rank;i<ncp;i+=stride){ - if(getPntrToComponent(i)->applyForce(forces)){ - for(unsigned j=0;j<nat;++j){ + #pragma omp for + for(unsigned i=rank; i<ncp; i+=stride) { + if(getPntrToComponent(i)->applyForce(forces)) { + for(unsigned j=0; j<nat; ++j) { omp_f[j][0]+=forces[3*j+0]; omp_f[j][1]+=forces[3*j+1]; omp_f[j][2]+=forces[3*j+2]; @@ -94,7 +94,7 @@ void Colvar::apply(){ } #pragma omp critical { - for(unsigned j=0;j<nat;++j) f[j]+=omp_f[j]; + for(unsigned j=0; j<nat; ++j) f[j]+=omp_f[j]; v+=omp_v; } } @@ -104,19 +104,19 @@ void Colvar::apply(){ comm.Sum(&v[0][0],9); } - } else if( isEnergy ){ + } else if( isEnergy ) { vector<double> forces(1); if(getPntrToComponent(0)->applyForce(forces)) modifyForceOnEnergy()+=forces[0]; } } -void Colvar::setBoxDerivativesNoPbc(Value* v){ +void Colvar::setBoxDerivativesNoPbc(Value* v) { Tensor virial; unsigned nat=getNumberOfAtoms(); - for(unsigned i=0;i<nat;i++) virial-=Tensor(getPosition(i), - Vector(v->getDerivative(3*i+0), - v->getDerivative(3*i+1), - v->getDerivative(3*i+2))); + for(unsigned i=0; i<nat; i++) virial-=Tensor(getPosition(i), + Vector(v->getDerivative(3*i+0), + v->getDerivative(3*i+1), + v->getDerivative(3*i+2))); setBoxDerivatives(v,virial); } } diff --git a/src/core/Colvar.h b/src/core/Colvar.h index 08e962aa5..4a7ef6a08 100644 --- a/src/core/Colvar.h +++ b/src/core/Colvar.h @@ -32,14 +32,14 @@ namespace PLMD { /** \ingroup INHERIT -This is the abstract base class to use for implementing new collective variables, within it there is -\ref AddingAColvar "information" as to how to go about implementing a new CV. +This is the abstract base class to use for implementing new collective variables, within it there is +\ref AddingAColvar "information" as to how to go about implementing a new CV. */ class Colvar : public ActionAtomistic, public ActionWithValue - { +{ private: protected: bool isEnergy; @@ -47,7 +47,7 @@ protected: // Set the derivatives for a particular atom equal to the input Vector // This routine is called setAtomsDerivatives because not because you // are setting the derivative of many atoms but because you are setting -// the derivatives of a particular atom. The s is an apostrophe s +// the derivatives of a particular atom. The s is an apostrophe s // but you can't put apostrophes in function names void setAtomsDerivatives(int,const Vector&); void setAtomsDerivatives(Value*,int,const Vector&); @@ -63,15 +63,15 @@ protected: void setBoxDerivativesNoPbc(); void setBoxDerivativesNoPbc(Value*); public: - bool checkIsEnergy(){return isEnergy;} + bool checkIsEnergy() {return isEnergy;} explicit Colvar(const ActionOptions&); - ~Colvar(){} + ~Colvar() {} static void registerKeywords( Keywords& keys ); virtual unsigned getNumberOfDerivatives(); }; inline -void Colvar::setAtomsDerivatives(Value*v,int i,const Vector&d){ +void Colvar::setAtomsDerivatives(Value*v,int i,const Vector&d) { v->addDerivative(3*i+0,d[0]); v->addDerivative(3*i+1,d[1]); v->addDerivative(3*i+2,d[2]); @@ -79,7 +79,7 @@ void Colvar::setAtomsDerivatives(Value*v,int i,const Vector&d){ inline -void Colvar::setBoxDerivatives(Value* v,const Tensor&d){ +void Colvar::setBoxDerivatives(Value* v,const Tensor&d) { unsigned nat=getNumberOfAtoms(); v->addDerivative(3*nat+0,d(0,0)); v->addDerivative(3*nat+1,d(0,1)); @@ -93,22 +93,22 @@ void Colvar::setBoxDerivatives(Value* v,const Tensor&d){ } inline -void Colvar::setAtomsDerivatives(int i,const Vector&d){ +void Colvar::setAtomsDerivatives(int i,const Vector&d) { setAtomsDerivatives(getPntrToValue(),i,d); } inline -void Colvar::setBoxDerivatives(const Tensor&d){ +void Colvar::setBoxDerivatives(const Tensor&d) { setBoxDerivatives(getPntrToValue(),d); } inline -void Colvar::setBoxDerivativesNoPbc(){ +void Colvar::setBoxDerivativesNoPbc() { setBoxDerivativesNoPbc(getPntrToValue()); } inline -unsigned Colvar::getNumberOfDerivatives(){ +unsigned Colvar::getNumberOfDerivatives() { return 3*getNumberOfAtoms() + 9; } diff --git a/src/core/ExchangePatterns.cpp b/src/core/ExchangePatterns.cpp index a3b4d338c..fdd22e74e 100644 --- a/src/core/ExchangePatterns.cpp +++ b/src/core/ExchangePatterns.cpp @@ -24,7 +24,7 @@ using namespace std; -namespace PLMD{ +namespace PLMD { ExchangePatterns::ExchangePatterns(): PatternFlag(NONE), @@ -37,15 +37,15 @@ ExchangePatterns::~ExchangePatterns() delete &random; } -void ExchangePatterns::setNofR(const int nrepl){ +void ExchangePatterns::setNofR(const int nrepl) { NumberOfReplicas=nrepl; } -void ExchangePatterns::setFlag(const int flag){ +void ExchangePatterns::setFlag(const int flag) { PatternFlag=flag; } -void ExchangePatterns::getFlag(int &flag){ +void ExchangePatterns::getFlag(int &flag) { flag=PatternFlag; } @@ -58,19 +58,19 @@ void ExchangePatterns::getList(int *ind) { switch(PatternFlag) { - case RANDOM: - for(int i=0;i<NumberOfReplicas;i++) { - int stat=1; - while(stat) { - stat=0; - ind[i] = (int) (random.U01()*NumberOfReplicas); - for(int j=0;j<i;j++) if(ind[i]==ind[j]) stat=1; - } + case RANDOM: + for(int i=0; i<NumberOfReplicas; i++) { + int stat=1; + while(stat) { + stat=0; + ind[i] = (int) (random.U01()*NumberOfReplicas); + for(int j=0; j<i; j++) if(ind[i]==ind[j]) stat=1; } - break; - case NEIGHBOR: - for(int i=0;i<NumberOfReplicas;i++) ind[i]=i; - break; + } + break; + case NEIGHBOR: + for(int i=0; i<NumberOfReplicas; i++) ind[i]=i; + break; } } diff --git a/src/core/ExchangePatterns.h b/src/core/ExchangePatterns.h index 4d9e307e6..14099be4d 100644 --- a/src/core/ExchangePatterns.h +++ b/src/core/ExchangePatterns.h @@ -25,10 +25,10 @@ namespace PLMD { class Random; - class ExchangePatterns { - int PatternFlag; - int NumberOfReplicas; - Random& random; +class ExchangePatterns { + int PatternFlag; + int NumberOfReplicas; + Random& random; public: ExchangePatterns(); ~ExchangePatterns(); diff --git a/src/core/FlexibleBin.cpp b/src/core/FlexibleBin.cpp index 136e6ed46..62198f98b 100644 --- a/src/core/FlexibleBin.cpp +++ b/src/core/FlexibleBin.cpp @@ -27,327 +27,327 @@ #include "tools/Matrix.h" using namespace std; -namespace PLMD{ +namespace PLMD { -FlexibleBin::FlexibleBin(int type, ActionWithArguments *paction, double const &d , vector<double> &smin, vector<double> &smax):type(type),paction(paction),sigma(d),sigmamin(smin),sigmamax(smax){ - // initialize the averages and the variance matrices - if(type==diffusion){ - unsigned ncv=paction->getNumberOfArguments(); - vector<double> average(ncv*(ncv+1)/2); - vector<double> variance(ncv*(ncv+1)/2); - } - paction->log<<" Limits for sigmas using adaptive hills: \n"; - for(unsigned i=0;i<paction->getNumberOfArguments();++i){ - paction->log<<" CV "<<paction->getPntrToArgument(i)->getName()<<":\n"; - if(sigmamin[i]>0.){ - limitmin.push_back(true); - paction->log<<" Min "<<sigmamin[i]; - sigmamin[i]*=sigmamin[i]; // this is because the matrix which is calculated is the sigmasquared - }else{ - limitmin.push_back(false); - paction->log<<" Min No "; - } - if(sigmamax[i]>0.){ - limitmax.push_back(true); - paction->log<<" Max "<<sigmamax[i]; - sigmamax[i]*=sigmamax[i]; - }else{ - limitmax.push_back(false); - paction->log<<" Max No "; - } - paction->log<<" \n"; - } +FlexibleBin::FlexibleBin(int type, ActionWithArguments *paction, double const &d, vector<double> &smin, vector<double> &smax):type(type),paction(paction),sigma(d),sigmamin(smin),sigmamax(smax) { + // initialize the averages and the variance matrices + if(type==diffusion) { + unsigned ncv=paction->getNumberOfArguments(); + vector<double> average(ncv*(ncv+1)/2); + vector<double> variance(ncv*(ncv+1)/2); + } + paction->log<<" Limits for sigmas using adaptive hills: \n"; + for(unsigned i=0; i<paction->getNumberOfArguments(); ++i) { + paction->log<<" CV "<<paction->getPntrToArgument(i)->getName()<<":\n"; + if(sigmamin[i]>0.) { + limitmin.push_back(true); + paction->log<<" Min "<<sigmamin[i]; + sigmamin[i]*=sigmamin[i]; // this is because the matrix which is calculated is the sigmasquared + } else { + limitmin.push_back(false); + paction->log<<" Min No "; + } + if(sigmamax[i]>0.) { + limitmax.push_back(true); + paction->log<<" Max "<<sigmamax[i]; + sigmamax[i]*=sigmamax[i]; + } else { + limitmax.push_back(false); + paction->log<<" Max No "; + } + paction->log<<" \n"; + } } /// Constructure for 1D FB for PBMETAD -FlexibleBin::FlexibleBin(int type, ActionWithArguments *paction, unsigned iarg, +FlexibleBin::FlexibleBin(int type, ActionWithArguments *paction, unsigned iarg, double const &d, vector<double> &smin, vector<double> &smax): - type(type),paction(paction),sigma(d),sigmamin(smin),sigmamax(smax) + type(type),paction(paction),sigma(d),sigmamin(smin),sigmamax(smax) { - // initialize the averages and the variance matrices - if(type==diffusion){ - vector<double> average(1); - vector<double> variance(1); - } - paction->log<<" Limits for sigmas using adaptive hills: \n"; - paction->log<<" CV "<<paction->getPntrToArgument(iarg)->getName()<<":\n"; - if(sigmamin[0]>0.){ - limitmin.push_back(true); - paction->log<<" Min "<<sigmamin[0]; - sigmamin[0]*=sigmamin[0]; - }else{ - limitmin.push_back(false); - paction->log<<" Min No "; - } - if(sigmamax[0]>0.){ - limitmax.push_back(true); - paction->log<<" Max "<<sigmamax[0]; - sigmamax[0]*=sigmamax[0]; - }else{ - limitmax.push_back(false); - paction->log<<" Max No "; - } - paction->log<<" \n"; + // initialize the averages and the variance matrices + if(type==diffusion) { + vector<double> average(1); + vector<double> variance(1); + } + paction->log<<" Limits for sigmas using adaptive hills: \n"; + paction->log<<" CV "<<paction->getPntrToArgument(iarg)->getName()<<":\n"; + if(sigmamin[0]>0.) { + limitmin.push_back(true); + paction->log<<" Min "<<sigmamin[0]; + sigmamin[0]*=sigmamin[0]; + } else { + limitmin.push_back(false); + paction->log<<" Min No "; + } + if(sigmamax[0]>0.) { + limitmax.push_back(true); + paction->log<<" Max "<<sigmamax[0]; + sigmamax[0]*=sigmamax[0]; + } else { + limitmax.push_back(false); + paction->log<<" Max No "; + } + paction->log<<" \n"; } -/// Update the flexible bin +/// Update the flexible bin /// in case of diffusion based: update at every step -/// in case of gradient based: update only when you add the hill -void FlexibleBin::update(bool nowAddAHill){ - unsigned ncv=paction->getNumberOfArguments(); - unsigned dimension=ncv*(ncv+1)/2; - // this is done all the times from scratch. It is not an accumulator - unsigned k=0; - unsigned i; - vector<double> cv; - vector<double> delta; - // if you use this below then the decay is in time units - //double decay=paction->getTimeStep()/sigma; - // to be consistent with the rest of the program: everything is better to be in timesteps - double decay=1./sigma; - // here update the flexible bin according to the needs - switch (type){ - // This should be called every time - case diffusion: - // - // THE AVERAGE VALUE - // - // beware: the pbc - delta.resize(ncv); - for(i=0;i<ncv;i++)cv.push_back(paction->getArgument(i)); - if(average.size()==0){ // initial time: just set the initial vector - average.resize(ncv); - for(i=0;i<ncv;i++)average[i]=cv[i]; - }else{ // accumulate - for(i=0;i<ncv;i++){ - delta[i]=paction->difference(i,average[i],cv[i]); - average[i]+=decay*delta[i]; - average[i]=paction->bringBackInPbc(i,average[i]); // equation 8 of "Metadynamics with adaptive Gaussians" - } +/// in case of gradient based: update only when you add the hill +void FlexibleBin::update(bool nowAddAHill) { + unsigned ncv=paction->getNumberOfArguments(); + unsigned dimension=ncv*(ncv+1)/2; + // this is done all the times from scratch. It is not an accumulator + unsigned k=0; + unsigned i; + vector<double> cv; + vector<double> delta; + // if you use this below then the decay is in time units + //double decay=paction->getTimeStep()/sigma; + // to be consistent with the rest of the program: everything is better to be in timesteps + double decay=1./sigma; + // here update the flexible bin according to the needs + switch (type) { + // This should be called every time + case diffusion: + // + // THE AVERAGE VALUE + // + // beware: the pbc + delta.resize(ncv); + for(i=0; i<ncv; i++)cv.push_back(paction->getArgument(i)); + if(average.size()==0) { // initial time: just set the initial vector + average.resize(ncv); + for(i=0; i<ncv; i++)average[i]=cv[i]; + } else { // accumulate + for(i=0; i<ncv; i++) { + delta[i]=paction->difference(i,average[i],cv[i]); + average[i]+=decay*delta[i]; + average[i]=paction->bringBackInPbc(i,average[i]); // equation 8 of "Metadynamics with adaptive Gaussians" + } - } - // - // THE VARIANCE - // - if(variance.size()==0){ - variance.resize(dimension,0.); // nonredundant members dimension=ncv*(ncv+1)/2; - }else{ - k=0; - for(i=0;i<ncv;i++){ - for(unsigned j=i;j<ncv;j++){ // upper diagonal loop - variance[k]+=decay*(delta[i]*delta[j]-variance[k]); - k++; - } - } - } - break; - case geometry: - // - //this calculates in variance the \nabla CV_i \dot \nabla CV_j - // - variance.resize(dimension); - //cerr<< "Doing geometry "<<endl; - // now the signal for retrieving the gradients should be already given by checkNeedsGradients. - // here just do the projections - // note that the call checkNeedsGradients() in BiasMetaD takes care of switching on the call to gradients - if (nowAddAHill){// geometry is sync with hill deposition - //cerr<< "add a hill "<<endl; - k=0; - for(unsigned i=0;i<ncv;i++){ - for(unsigned j=i;j<ncv;j++){ - // eq 12 of "Metadynamics with adaptive Gaussians" - variance[k]=sigma*sigma*(paction->getProjection(i,j)); - k++; - } - }; - }; - break; - default: - cerr<< "This flexible bin is not recognized "<<endl; - exit(1) ; - } + } + // + // THE VARIANCE + // + if(variance.size()==0) { + variance.resize(dimension,0.); // nonredundant members dimension=ncv*(ncv+1)/2; + } else { + k=0; + for(i=0; i<ncv; i++) { + for(unsigned j=i; j<ncv; j++) { // upper diagonal loop + variance[k]+=decay*(delta[i]*delta[j]-variance[k]); + k++; + } + } + } + break; + case geometry: + // + //this calculates in variance the \nabla CV_i \dot \nabla CV_j + // + variance.resize(dimension); + //cerr<< "Doing geometry "<<endl; + // now the signal for retrieving the gradients should be already given by checkNeedsGradients. + // here just do the projections + // note that the call checkNeedsGradients() in BiasMetaD takes care of switching on the call to gradients + if (nowAddAHill) { // geometry is sync with hill deposition + //cerr<< "add a hill "<<endl; + k=0; + for(unsigned i=0; i<ncv; i++) { + for(unsigned j=i; j<ncv; j++) { + // eq 12 of "Metadynamics with adaptive Gaussians" + variance[k]=sigma*sigma*(paction->getProjection(i,j)); + k++; + } + }; + }; + break; + default: + cerr<< "This flexible bin is not recognized "<<endl; + exit(1) ; + } } -vector<double> FlexibleBin::getMatrix() const{ - return variance; +vector<double> FlexibleBin::getMatrix() const { + return variance; } /// Update the flexible bin for PBMetaD like FlexBin /// in case of diffusion based: update at every step -/// in case of gradient based: update only when you add the hill -void FlexibleBin::update(bool nowAddAHill, unsigned iarg){ - // this is done all the times from scratch. It is not an accumulator - vector<double> cv; - vector<double> delta; - // if you use this below then the decay is in time units - // to be consistent with the rest of the program: everything is better to be in timesteps - double decay=1./sigma; - // here update the flexible bin according to the needs - switch (type){ - // This should be called every time - case diffusion: - // - // THE AVERAGE VALUE - // - delta.resize(1); - cv.push_back(paction->getArgument(iarg)); - if(average.size()==0){ // initial time: just set the initial vector - average.resize(1); - average[0]=cv[0]; - }else{ // accumulate - delta[0]=paction->difference(iarg,average[0],cv[0]); - average[0]+=decay*delta[0]; - average[0]=paction->bringBackInPbc(iarg,average[0]); // equation 8 of "Metadynamics with adaptive Gaussians" - } - // - // THE VARIANCE - // - if(variance.size()==0){ - variance.resize(1,0.); // nonredundant members dimension=ncv*(ncv+1)/2; - }else{ - variance[0]+=decay*(delta[0]*delta[0]-variance[0]); - } - break; - case geometry: - // - //this calculates in variance the \nabla CV_i \dot \nabla CV_j - // - variance.resize(1); - // now the signal for retrieving the gradients should be already given by checkNeedsGradients. - // here just do the projections - // note that the call checkNeedsGradients() in BiasMetaD takes care of switching on the call to gradients - if (nowAddAHill){// geometry is sync with hill deposition - // eq 12 of "Metadynamics with adaptive Gaussians" - variance[0]=sigma*sigma*(paction->getProjection(iarg,iarg)); - } - break; - default: - cerr<< "This flexible bin is not recognized "<<endl; - exit(1) ; - } +/// in case of gradient based: update only when you add the hill +void FlexibleBin::update(bool nowAddAHill, unsigned iarg) { + // this is done all the times from scratch. It is not an accumulator + vector<double> cv; + vector<double> delta; + // if you use this below then the decay is in time units + // to be consistent with the rest of the program: everything is better to be in timesteps + double decay=1./sigma; + // here update the flexible bin according to the needs + switch (type) { + // This should be called every time + case diffusion: + // + // THE AVERAGE VALUE + // + delta.resize(1); + cv.push_back(paction->getArgument(iarg)); + if(average.size()==0) { // initial time: just set the initial vector + average.resize(1); + average[0]=cv[0]; + } else { // accumulate + delta[0]=paction->difference(iarg,average[0],cv[0]); + average[0]+=decay*delta[0]; + average[0]=paction->bringBackInPbc(iarg,average[0]); // equation 8 of "Metadynamics with adaptive Gaussians" + } + // + // THE VARIANCE + // + if(variance.size()==0) { + variance.resize(1,0.); // nonredundant members dimension=ncv*(ncv+1)/2; + } else { + variance[0]+=decay*(delta[0]*delta[0]-variance[0]); + } + break; + case geometry: + // + //this calculates in variance the \nabla CV_i \dot \nabla CV_j + // + variance.resize(1); + // now the signal for retrieving the gradients should be already given by checkNeedsGradients. + // here just do the projections + // note that the call checkNeedsGradients() in BiasMetaD takes care of switching on the call to gradients + if (nowAddAHill) { // geometry is sync with hill deposition + // eq 12 of "Metadynamics with adaptive Gaussians" + variance[0]=sigma*sigma*(paction->getProjection(iarg,iarg)); + } + break; + default: + cerr<< "This flexible bin is not recognized "<<endl; + exit(1) ; + } } /// -/// Calculate the matrix of (dcv_i/dx)*(dcv_j/dx)^-1 +/// Calculate the matrix of (dcv_i/dx)*(dcv_j/dx)^-1 /// that is needed for the metrics in metadynamics /// /// -vector<double> FlexibleBin::getInverseMatrix() const{ - unsigned ncv=paction->getNumberOfArguments(); - Matrix<double> matrix(ncv,ncv); - unsigned i,j,k; - k=0; - //paction->log<<"------------ GET INVERSE MATRIX ---------------\n"; - // place the matrix in a complete matrix for compatibility - for (i=0;i<ncv;i++){ - for (j=i;j<ncv;j++){ - matrix(j,i)=matrix(i,j)=variance[k]; - k++; - } - } +vector<double> FlexibleBin::getInverseMatrix() const { + unsigned ncv=paction->getNumberOfArguments(); + Matrix<double> matrix(ncv,ncv); + unsigned i,j,k; + k=0; + //paction->log<<"------------ GET INVERSE MATRIX ---------------\n"; + // place the matrix in a complete matrix for compatibility + for (i=0; i<ncv; i++) { + for (j=i; j<ncv; j++) { + matrix(j,i)=matrix(i,j)=variance[k]; + k++; + } + } #define NEWFLEX #ifdef NEWFLEX - // diagonalize to impose boundaries (only if boundaries are set) - Matrix<double> eigenvecs(ncv,ncv); - vector<double> eigenvals(ncv); + // diagonalize to impose boundaries (only if boundaries are set) + Matrix<double> eigenvecs(ncv,ncv); + vector<double> eigenvals(ncv); - //eigenvecs: first is eigenvec number, second is eigenvec component - if(diagMat( matrix , eigenvals , eigenvecs )!=0){plumed_merror("diagonalization in FlexibleBin failed! This matrix is weird\n");}; - - for (i=0;i<ncv;i++){//loop on the dimension - if( limitmax[i] ){ - //limit every component that is larger - for (j=0;j<ncv;j++){//loop on components - if(pow(eigenvals[j]*eigenvecs[j][i],2)>pow(sigmamax[i],2) ){ - eigenvals[j]=sqrt(pow(sigmamax[i]/(eigenvecs[j][i]),2))*copysign(1.,eigenvals[j]); - } - } - } - } - for (i=0;i<ncv;i++){//loop on the dimension - // find the largest one: if it is smaller than min then rescale - if( limitmin[i] ){ - unsigned imax=0; - double fmax=-1.e10; - for (j=0;j<ncv;j++){//loop on components - double fact=pow(eigenvals[j]*eigenvecs[j][i],2); - if(fact>fmax){ - fmax=fact;imax=j; - } - } - if(fmax<pow(sigmamin[i],2) ){ - eigenvals[imax]=sqrt(pow(sigmamin[i]/(eigenvecs[imax][i]),2))*copysign(1.,eigenvals[imax]); - } - } - } + //eigenvecs: first is eigenvec number, second is eigenvec component + if(diagMat( matrix, eigenvals, eigenvecs )!=0) {plumed_merror("diagonalization in FlexibleBin failed! This matrix is weird\n");}; - // normalize eigenvecs - Matrix<double> newinvmatrix(ncv,ncv); - for (i=0;i<ncv;i++){ - for (j=0;j<ncv;j++){ - newinvmatrix[j][i]=eigenvecs[j][i]/eigenvals[j]; - } - } + for (i=0; i<ncv; i++) { //loop on the dimension + if( limitmax[i] ) { + //limit every component that is larger + for (j=0; j<ncv; j++) { //loop on components + if(pow(eigenvals[j]*eigenvecs[j][i],2)>pow(sigmamax[i],2) ) { + eigenvals[j]=sqrt(pow(sigmamax[i]/(eigenvecs[j][i]),2))*copysign(1.,eigenvals[j]); + } + } + } + } + for (i=0; i<ncv; i++) { //loop on the dimension + // find the largest one: if it is smaller than min then rescale + if( limitmin[i] ) { + unsigned imax=0; + double fmax=-1.e10; + for (j=0; j<ncv; j++) { //loop on components + double fact=pow(eigenvals[j]*eigenvecs[j][i],2); + if(fact>fmax) { + fmax=fact; imax=j; + } + } + if(fmax<pow(sigmamin[i],2) ) { + eigenvals[imax]=sqrt(pow(sigmamin[i]/(eigenvecs[imax][i]),2))*copysign(1.,eigenvals[imax]); + } + } + } - vector<double> uppervec(ncv*(ncv+1)/2); - k=0; - for (i=0;i<ncv;i++){ - for (j=i;j<ncv;j++){ - double scal=0; - for(unsigned l=0;l<ncv;++l){ - scal+=eigenvecs[l][i]*newinvmatrix[l][j]; - } - uppervec[k]=scal; k++; - } - } -#else - // get the inverted matrix - Matrix<double> invmatrix(ncv,ncv); - Invert(matrix,invmatrix); - vector<double> uppervec(ncv*(ncv+1)/2); - // upper diagonal of the inverted matrix (that is symmetric) - k=0; - for (i=0;i<ncv;i++){ - for (j=i;j<ncv;j++){ - uppervec[k]=invmatrix(i,j); - //paction->log<<"VV "<<i<<" "<<j<<" "<<uppervec[k]<<"\n"; - k++; - } - } + // normalize eigenvecs + Matrix<double> newinvmatrix(ncv,ncv); + for (i=0; i<ncv; i++) { + for (j=0; j<ncv; j++) { + newinvmatrix[j][i]=eigenvecs[j][i]/eigenvals[j]; + } + } + + vector<double> uppervec(ncv*(ncv+1)/2); + k=0; + for (i=0; i<ncv; i++) { + for (j=i; j<ncv; j++) { + double scal=0; + for(unsigned l=0; l<ncv; ++l) { + scal+=eigenvecs[l][i]*newinvmatrix[l][j]; + } + uppervec[k]=scal; k++; + } + } +#else + // get the inverted matrix + Matrix<double> invmatrix(ncv,ncv); + Invert(matrix,invmatrix); + vector<double> uppervec(ncv*(ncv+1)/2); + // upper diagonal of the inverted matrix (that is symmetric) + k=0; + for (i=0; i<ncv; i++) { + for (j=i; j<ncv; j++) { + uppervec[k]=invmatrix(i,j); + //paction->log<<"VV "<<i<<" "<<j<<" "<<uppervec[k]<<"\n"; + k++; + } + } #endif - return uppervec; + return uppervec; } /// -/// Calculate the matrix of (dcv_i/dx)*(dcv_j/dx)^-1 +/// Calculate the matrix of (dcv_i/dx)*(dcv_j/dx)^-1 /// that is needed for the metrics in metadynamics /// for PBMetaD like FlexBin /// -vector<double> FlexibleBin::getInverseMatrix(unsigned iarg) const{ - // diagonalize to impose boundaries (only if boundaries are set) - vector<double> eigenvals(1, variance[0]); - if( limitmax[0] ){ - if(eigenvals[0]>sigmamax[0]){ - eigenvals[0]=sigmamax[0]; - } - } - // find the largest one: if it is smaller than min then rescale - if( limitmin[0] ){ - double fmax=-1.e10; - double fact=eigenvals[0]; - if(fact>fmax){ - fmax=fact; - } - if(fmax<sigmamin[0]){ - eigenvals[0]=sigmamin[0]; - } - } - vector<double> uppervec(1,1./eigenvals[0]); +vector<double> FlexibleBin::getInverseMatrix(unsigned iarg) const { + // diagonalize to impose boundaries (only if boundaries are set) + vector<double> eigenvals(1, variance[0]); + if( limitmax[0] ) { + if(eigenvals[0]>sigmamax[0]) { + eigenvals[0]=sigmamax[0]; + } + } + // find the largest one: if it is smaller than min then rescale + if( limitmin[0] ) { + double fmax=-1.e10; + double fact=eigenvals[0]; + if(fact>fmax) { + fmax=fact; + } + if(fmax<sigmamin[0]) { + eigenvals[0]=sigmamin[0]; + } + } + vector<double> uppervec(1,1./eigenvals[0]); - return uppervec; + return uppervec; } } diff --git a/src/core/FlexibleBin.h b/src/core/FlexibleBin.h index 4bd942a07..3bcbd16f0 100644 --- a/src/core/FlexibleBin.h +++ b/src/core/FlexibleBin.h @@ -24,37 +24,37 @@ #include<vector> -namespace PLMD{ +namespace PLMD { class ActionWithArguments; -class FlexibleBin{ - private: - int type; - // this contains all the infos about the CVs including periodicity - ActionWithArguments *paction; - double sigma; - // variance is the matrix that really matters - std::vector<double> variance; - // this is only there - std::vector<double> average; - // minimum and maximum values - std::vector<double> sigmamin; - std::vector<double> sigmamax; - std::vector<bool> limitmax; - std::vector<bool> limitmin; - public: - /// a constructor that takes the pointer of the action that contains it - FlexibleBin(int type,ActionWithArguments *paction, double const &d, std::vector<double> &sigmamin, std::vector<double> &sigmamax ); - /// a constructor for 1D FlexBin (for PBMETAD) - FlexibleBin(int type, ActionWithArguments *paction, unsigned iarg, double const &d, std::vector<double> &sigmamin, std::vector<double> &sigmamax); - /// update the average (always for diffusion) or calculate the geom covariance ( only when do_when_zero is zero) - void update(bool nowAddAHill); - void update(bool nowAddAHill, unsigned iarg); - std::vector<double> getMatrix() const; - std::vector<double> getInverseMatrix() const; - std::vector<double> getInverseMatrix(unsigned iarg) const; - enum AdaptiveHillsType { none, diffusion, geometry }; +class FlexibleBin { +private: + int type; + // this contains all the infos about the CVs including periodicity + ActionWithArguments *paction; + double sigma; + // variance is the matrix that really matters + std::vector<double> variance; + // this is only there + std::vector<double> average; + // minimum and maximum values + std::vector<double> sigmamin; + std::vector<double> sigmamax; + std::vector<bool> limitmax; + std::vector<bool> limitmin; +public: + /// a constructor that takes the pointer of the action that contains it + FlexibleBin(int type,ActionWithArguments *paction, double const &d, std::vector<double> &sigmamin, std::vector<double> &sigmamax ); + /// a constructor for 1D FlexBin (for PBMETAD) + FlexibleBin(int type, ActionWithArguments *paction, unsigned iarg, double const &d, std::vector<double> &sigmamin, std::vector<double> &sigmamax); + /// update the average (always for diffusion) or calculate the geom covariance ( only when do_when_zero is zero) + void update(bool nowAddAHill); + void update(bool nowAddAHill, unsigned iarg); + std::vector<double> getMatrix() const; + std::vector<double> getInverseMatrix() const; + std::vector<double> getInverseMatrix(unsigned iarg) const; + enum AdaptiveHillsType { none, diffusion, geometry }; }; diff --git a/src/core/GREX.cpp b/src/core/GREX.cpp index 9e355ece1..fb30166a3 100644 --- a/src/core/GREX.cpp +++ b/src/core/GREX.cpp @@ -30,12 +30,12 @@ #include "GREXEnum.inc" using namespace std; -namespace PLMD{ +namespace PLMD { -const std::unordered_map<std::string, int> & GREXWordMap(){ +const std::unordered_map<std::string, int> & GREXWordMap() { static std::unordered_map<std::string, int> word_map; static bool init=false; - if(!init){ + if(!init) { #include "GREXMap.inc" } init=true; @@ -58,7 +58,7 @@ GREX::GREX(PlumedMain&p): p.setSuffix(".NA"); } -GREX::~GREX(){ +GREX::~GREX() { delete &intercomm; delete &intracomm; } @@ -67,16 +67,16 @@ GREX::~GREX(){ #define CHECK_NOTINIT(ini,word) plumed_massert(!(ini),"cmd(\"" + word +"\") should be only used before GREX initialization") #define CHECK_NOTNULL(val,word) plumed_massert(val,"NULL pointer received in cmd(\"GREX " + word + "\")"); -void GREX::cmd(const string&key,void*val){ +void GREX::cmd(const string&key,void*val) { std::vector<std::string> words=Tools::getWords(key); unsigned nw=words.size(); - if(nw==0){ + if(nw==0) { // do nothing } else { int iword=-1; const auto it=GREXWordMap().find(words[0]); if(it!=GREXWordMap().end()) iword=it->second; - switch(iword){ + switch(iword) { case cmd_initialized: CHECK_NOTNULL(val,key); *static_cast<int*>(val)=initialized; @@ -173,7 +173,7 @@ void GREX::cmd(const string&key,void*val){ CHECK_NOTNULL(val,key); plumed_assert(nw==2); plumed_massert(allDeltaBias.size()==static_cast<unsigned>(intercomm.Get_size()), - "to retrieve bias with cmd(\"GREX getDeltaBias\"), first share it with cmd(\"GREX shareAllDeltaBias\")"); + "to retrieve bias with cmd(\"GREX getDeltaBias\"), first share it with cmd(\"GREX shareAllDeltaBias\")"); { unsigned rep; Tools::convert(words[1],rep); @@ -189,7 +189,7 @@ void GREX::cmd(const string&key,void*val){ } } -void GREX::savePositions(){ +void GREX::savePositions() { plumedMain.prepareDependencies(); plumedMain.resetActive(true); atoms.shareAll(); @@ -199,12 +199,12 @@ void GREX::savePositions(){ buffer=o.str(); } -void GREX::calculate(){ +void GREX::calculate() { //fprintf(stderr,"CALCULATE %d %d\n",intercomm.Get_rank(),partner); unsigned nn=buffer.size(); vector<char> rbuf(nn); localDeltaBias=-plumedMain.getBias(); - if(intracomm.Get_rank()==0){ + if(intracomm.Get_rank()==0) { Communicator::Request req=intercomm.Isend(buffer,partner,1066); intercomm.Recv(rbuf,partner,1066); req.wait(); @@ -218,7 +218,7 @@ void GREX::calculate(){ plumedMain.setExchangeStep(false); localDeltaBias+=plumedMain.getBias(); localDeltaBias+=localUSwap-localUNow; - if(intracomm.Get_rank()==0){ + if(intracomm.Get_rank()==0) { Communicator::Request req=intercomm.Isend(localDeltaBias,partner,1067); intercomm.Recv(foreignDeltaBias,partner,1067); req.wait(); diff --git a/src/core/GREX.h b/src/core/GREX.h index 3a2553e4c..2266d1581 100644 --- a/src/core/GREX.h +++ b/src/core/GREX.h @@ -26,7 +26,7 @@ #include <string> #include <vector> -namespace PLMD{ +namespace PLMD { class PlumedMain; class Atoms; diff --git a/src/core/MDAtoms.cpp b/src/core/MDAtoms.cpp index ba95c8fac..1f11ad9cd 100644 --- a/src/core/MDAtoms.cpp +++ b/src/core/MDAtoms.cpp @@ -35,7 +35,7 @@ namespace PLMD { /// IT IS STILL UNDOCUMENTED. IT PROBABLY NEEDS A STRONG CLEANUP template <class T> class MDAtomsTyped: -public MDAtomsBase + public MDAtomsBase { T scalep,scalef; T scaleb,scalev; @@ -58,13 +58,13 @@ public: void setp(void*p,int i); void setf(void*f,int i); void setUnits(const Units&,const Units&); - void MD2double(const void*m,double&d)const{ + void MD2double(const void*m,double&d)const { d=double(*(static_cast<const T*>(m))); } - void double2MD(const double&d,void*m)const{ + void double2MD(const double&d,void*m)const { *(static_cast<T*>(m))=T(d); } - Vector getMDforces(const unsigned index)const{ + Vector getMDforces(const unsigned index)const { Vector force(fx[stride*index],fy[stride*index],fz[stride*index]); return force/scalef; } @@ -81,7 +81,7 @@ public: }; template <class T> -void MDAtomsTyped<T>::setUnits(const Units& units,const Units& MDUnits){ +void MDAtomsTyped<T>::setUnits(const Units& units,const Units& MDUnits) { double lscale=units.getLength()/MDUnits.getLength(); double escale=units.getEnergy()/MDUnits.getEnergy(); double cscale=units.getCharge()/MDUnits.getCharge(); @@ -97,15 +97,15 @@ void MDAtomsTyped<T>::setUnits(const Units& units,const Units& MDUnits){ } template <class T> -void MDAtomsTyped<T>::getBox(Tensor&box)const{ - if(this->box) for(int i=0;i<3;i++)for(int j=0;j<3;j++) box(i,j)=this->box[3*i+j]*scaleb; +void MDAtomsTyped<T>::getBox(Tensor&box)const { + if(this->box) for(int i=0; i<3; i++)for(int j=0; j<3; j++) box(i,j)=this->box[3*i+j]*scaleb; else box.zero(); } template <class T> -void MDAtomsTyped<T>::getPositions(const vector<int>&index,vector<Vector>&positions)const{ +void MDAtomsTyped<T>::getPositions(const vector<int>&index,vector<Vector>&positions)const { // cannot be parallelized with omp because access to positions is not ordered - for(unsigned i=0;i<index.size();++i){ + for(unsigned i=0; i<index.size(); ++i) { positions[index[i]][0]=px[stride*i]*scalep; positions[index[i]][1]=py[stride*i]*scalep; positions[index[i]][2]=pz[stride*i]*scalep; @@ -113,9 +113,9 @@ void MDAtomsTyped<T>::getPositions(const vector<int>&index,vector<Vector>&positi } template <class T> -void MDAtomsTyped<T>::getPositions(unsigned j,unsigned k,vector<Vector>&positions)const{ +void MDAtomsTyped<T>::getPositions(unsigned j,unsigned k,vector<Vector>&positions)const { #pragma omp parallel for num_threads(OpenMP::getGoodNumThreads(&positions[j],(k-j))) - for(unsigned i=j;i<k;++i){ + for(unsigned i=j; i<k; ++i) { positions[i][0]=px[stride*i]*scalep; positions[i][1]=py[stride*i]*scalep; positions[i][2]=pz[stride*i]*scalep; @@ -124,9 +124,9 @@ void MDAtomsTyped<T>::getPositions(unsigned j,unsigned k,vector<Vector>&position template <class T> -void MDAtomsTyped<T>::getLocalPositions(vector<Vector>&positions)const{ +void MDAtomsTyped<T>::getLocalPositions(vector<Vector>&positions)const { #pragma omp parallel for num_threads(OpenMP::getGoodNumThreads(positions)) - for(unsigned i=0;i<positions.size();++i){ + for(unsigned i=0; i<positions.size(); ++i) { positions[i][0]=px[stride*i]*scalep; positions[i][1]=py[stride*i]*scalep; positions[i][2]=pz[stride*i]*scalep; @@ -135,26 +135,26 @@ void MDAtomsTyped<T>::getLocalPositions(vector<Vector>&positions)const{ template <class T> -void MDAtomsTyped<T>::getMasses(const vector<int>&index,vector<double>&masses)const{ - if(m) for(unsigned i=0;i<index.size();++i) masses[index[i]]=scalem*m[i]; - else for(unsigned i=0;i<index.size();++i) masses[index[i]]=0.0; +void MDAtomsTyped<T>::getMasses(const vector<int>&index,vector<double>&masses)const { + if(m) for(unsigned i=0; i<index.size(); ++i) masses[index[i]]=scalem*m[i]; + else for(unsigned i=0; i<index.size(); ++i) masses[index[i]]=0.0; } template <class T> -void MDAtomsTyped<T>::getCharges(const vector<int>&index,vector<double>&charges)const{ - if(c) for(unsigned i=0;i<index.size();++i) charges[index[i]]=scalec*c[i]; - else for(unsigned i=0;i<index.size();++i) charges[index[i]]=0.0; +void MDAtomsTyped<T>::getCharges(const vector<int>&index,vector<double>&charges)const { + if(c) for(unsigned i=0; i<index.size(); ++i) charges[index[i]]=scalec*c[i]; + else for(unsigned i=0; i<index.size(); ++i) charges[index[i]]=0.0; } template <class T> -void MDAtomsTyped<T>::updateVirial(const Tensor&virial)const{ - if(this->virial) for(int i=0;i<3;i++)for(int j=0;j<3;j++) this->virial[3*i+j]+=T(virial(i,j)*scalev); +void MDAtomsTyped<T>::updateVirial(const Tensor&virial)const { + if(this->virial) for(int i=0; i<3; i++)for(int j=0; j<3; j++) this->virial[3*i+j]+=T(virial(i,j)*scalev); } template <class T> -void MDAtomsTyped<T>::updateForces(const vector<int>&index,const vector<Vector>&forces){ +void MDAtomsTyped<T>::updateForces(const vector<int>&index,const vector<Vector>&forces) { #pragma omp parallel for num_threads(OpenMP::getGoodNumThreads(fx,stride*index.size())) - for(unsigned i=0;i<index.size();++i){ + for(unsigned i=0; i<index.size(); ++i) { fx[stride*i]+=scalef*T(forces[index[i]][0]); fy[stride*i]+=scalef*T(forces[index[i]][1]); fz[stride*i]+=scalef*T(forces[index[i]][2]); @@ -162,10 +162,10 @@ void MDAtomsTyped<T>::updateForces(const vector<int>&index,const vector<Vector>& } template <class T> -void MDAtomsTyped<T>::rescaleForces(const vector<int>&index,double factor){ - if(virial) for(unsigned i=0;i<3;i++)for(unsigned j=0;j<3;j++) virial[3*i+j]*=T(factor); +void MDAtomsTyped<T>::rescaleForces(const vector<int>&index,double factor) { + if(virial) for(unsigned i=0; i<3; i++)for(unsigned j=0; j<3; j++) virial[3*i+j]*=T(factor); #pragma omp parallel for num_threads(OpenMP::getGoodNumThreads(fx,stride*index.size())) - for(unsigned i=0;i<index.size();++i){ + for(unsigned i=0; i<index.size(); ++i) { fx[stride*i]*=T(factor); fy[stride*i]*=T(factor); fz[stride*i]*=T(factor); @@ -173,12 +173,12 @@ void MDAtomsTyped<T>::rescaleForces(const vector<int>&index,double factor){ } template <class T> -unsigned MDAtomsTyped<T>::getRealPrecision()const{ +unsigned MDAtomsTyped<T>::getRealPrecision()const { return sizeof(T); } template <class T> -void MDAtomsTyped<T>::setp(void*pp){ +void MDAtomsTyped<T>::setp(void*pp) { T*p=static_cast<T*>(pp); plumed_assert(stride==0 || stride==3); px=p; @@ -188,13 +188,13 @@ void MDAtomsTyped<T>::setp(void*pp){ } template <class T> -void MDAtomsTyped<T>::setBox(void*pp){ +void MDAtomsTyped<T>::setBox(void*pp) { box=static_cast<T*>(pp); } template <class T> -void MDAtomsTyped<T>::setf(void*ff){ +void MDAtomsTyped<T>::setf(void*ff) { T*f=static_cast<T*>(ff); plumed_assert(stride==0 || stride==3); fx=f; @@ -204,7 +204,7 @@ void MDAtomsTyped<T>::setf(void*ff){ } template <class T> -void MDAtomsTyped<T>::setp(void*pp,int i){ +void MDAtomsTyped<T>::setp(void*pp,int i) { T*p=static_cast<T*>(pp); plumed_assert(stride==0 || stride==1); if(i==0)px=p; @@ -214,13 +214,13 @@ void MDAtomsTyped<T>::setp(void*pp,int i){ } template <class T> -void MDAtomsTyped<T>::setVirial(void*pp){ +void MDAtomsTyped<T>::setVirial(void*pp) { virial=static_cast<T*>(pp); } template <class T> -void MDAtomsTyped<T>::setf(void*ff,int i){ +void MDAtomsTyped<T>::setf(void*ff,int i) { T*f=static_cast<T*>(ff); plumed_assert(stride==0 || stride==1); if(i==0)fx=f; @@ -230,12 +230,12 @@ void MDAtomsTyped<T>::setf(void*ff,int i){ } template <class T> -void MDAtomsTyped<T>::setm(void*m){ +void MDAtomsTyped<T>::setm(void*m) { this->m=static_cast<T*>(m); } template <class T> -void MDAtomsTyped<T>::setc(void*c){ +void MDAtomsTyped<T>::setc(void*c) { this->c=static_cast<T*>(c); } @@ -260,10 +260,10 @@ MDAtomsTyped<T>::MDAtomsTyped(): virial(NULL) {} -MDAtomsBase* MDAtomsBase::create(unsigned p){ - if(p==sizeof(double)){ +MDAtomsBase* MDAtomsBase::create(unsigned p) { + if(p==sizeof(double)) { return new MDAtomsTyped<double>; - } else if (p==sizeof(float)){ + } else if (p==sizeof(float)) { return new MDAtomsTyped<float>; } std::string pp; diff --git a/src/core/MDAtoms.h b/src/core/MDAtoms.h index 04932a21f..3926d47f1 100644 --- a/src/core/MDAtoms.h +++ b/src/core/MDAtoms.h @@ -51,7 +51,7 @@ public: /// Creates an MDAtomsTyped<T> object such that sizeof(T)==n static MDAtomsBase* create(unsigned n); /// Virtual destructor, just to allow inheritance. - virtual ~MDAtomsBase(){} + virtual ~MDAtomsBase() {} /// Get the size of MD-real virtual unsigned getRealPrecision()const=0; /// Set a pointer to the mass array in the MD code diff --git a/src/core/PlumedMain.cpp b/src/core/PlumedMain.cpp index ff4e9b79f..dd96581db 100644 --- a/src/core/PlumedMain.cpp +++ b/src/core/PlumedMain.cpp @@ -49,12 +49,12 @@ using namespace std; #include "PlumedMainEnum.inc" -namespace PLMD{ +namespace PLMD { -const std::unordered_map<std::string, int> & plumedMainWordMap(){ +const std::unordered_map<std::string, int> & plumedMainWordMap() { static std::unordered_map<std::string, int> word_map; static bool init=false; - if(!init){ + if(!init) { #include "PlumedMainMap.inc" } init=true; @@ -92,7 +92,7 @@ PlumedMain::PlumedMain(): stopwatch.pause(); } -PlumedMain::~PlumedMain(){ +PlumedMain::~PlumedMain() { stopwatch.start(); stopwatch.stop(); if(initialized) log<<stopwatch; @@ -117,13 +117,13 @@ PlumedMain::~PlumedMain(){ #define CHECK_NOTNULL(val,word) plumed_massert(val,"NULL pointer received in cmd(\"" + word + "\")"); -void PlumedMain::cmd(const std::string & word,void*val){ +void PlumedMain::cmd(const std::string & word,void*val) { stopwatch.start(); std::vector<std::string> words=Tools::getWords(word); unsigned nw=words.size(); - if(nw==0){ + if(nw==0) { // do nothing } else { int iword=-1; @@ -131,333 +131,333 @@ void PlumedMain::cmd(const std::string & word,void*val){ const auto it=plumedMainWordMap().find(words[0]); if(it!=plumedMainWordMap().end()) iword=it->second; switch(iword) { - case cmd_setBox: - CHECK_INIT(initialized,word); - CHECK_NOTNULL(val,word); - atoms.setBox(val); - break; - case cmd_setPositions: - CHECK_INIT(initialized,word); - atoms.setPositions(val); - break; - case cmd_setMasses: - CHECK_INIT(initialized,word); - atoms.setMasses(val); - break; - case cmd_setCharges: - CHECK_INIT(initialized,word); - atoms.setCharges(val); - break; - case cmd_setPositionsX: - CHECK_INIT(initialized,word); - atoms.setPositions(val,0); - break; - case cmd_setPositionsY: - CHECK_INIT(initialized,word); - atoms.setPositions(val,1); - break; - case cmd_setPositionsZ: - CHECK_INIT(initialized,word); - atoms.setPositions(val,2); - break; - case cmd_setVirial: - CHECK_INIT(initialized,word); - CHECK_NOTNULL(val,word); - atoms.setVirial(val); - break; - case cmd_setEnergy: - CHECK_INIT(initialized,word); - CHECK_NOTNULL(val,word); - atoms.setEnergy(val); - break; - case cmd_setForces: - CHECK_INIT(initialized,word); - atoms.setForces(val); - break; - case cmd_setForcesX: - CHECK_INIT(initialized,word); - atoms.setForces(val,0); - break; - case cmd_setForcesY: - CHECK_INIT(initialized,word); - atoms.setForces(val,1); - break; - case cmd_setForcesZ: - CHECK_INIT(initialized,word); - atoms.setForces(val,2); - break; - case cmd_calc: - CHECK_INIT(initialized,word); - calc(); - break; - case cmd_prepareDependencies: - CHECK_INIT(initialized,word); - prepareDependencies(); - break; - case cmd_shareData: - CHECK_INIT(initialized,word); - shareData(); - break; - case cmd_prepareCalc: - CHECK_INIT(initialized,word); - prepareCalc(); - break; - case cmd_performCalc: - CHECK_INIT(initialized,word); - performCalc(); - break; - case cmd_performCalcNoUpdate: - CHECK_INIT(initialized,word); - performCalcNoUpdate(); - break; - case cmd_update: - CHECK_INIT(initialized,word); - update(); - break; - case cmd_setStep: - CHECK_INIT(initialized,word); - CHECK_NOTNULL(val,word); - step=(*static_cast<int*>(val)); - atoms.startStep(); - break; - case cmd_setStepLong: - CHECK_INIT(initialized,word); - CHECK_NOTNULL(val,word); - step=(*static_cast<long int*>(val)); - atoms.startStep(); - break; - // words used less frequently: - case cmd_setAtomsNlocal: - CHECK_INIT(initialized,word); - CHECK_NOTNULL(val,word); - atoms.setAtomsNlocal(*static_cast<int*>(val)); - break; - case cmd_setAtomsGatindex: - CHECK_INIT(initialized,word); - atoms.setAtomsGatindex(static_cast<int*>(val),false); - break; - case cmd_setAtomsFGatindex: - CHECK_INIT(initialized,word); - atoms.setAtomsGatindex(static_cast<int*>(val),true); - break; - case cmd_setAtomsContiguous: - CHECK_INIT(initialized,word); - CHECK_NOTNULL(val,word); - atoms.setAtomsContiguous(*static_cast<int*>(val)); - break; - case cmd_createFullList: - CHECK_INIT(initialized,word); - CHECK_NOTNULL(val,word); - atoms.createFullList(static_cast<int*>(val)); - break; - case cmd_getFullList: - CHECK_INIT(initialized,word); - CHECK_NOTNULL(val,word); - atoms.getFullList(static_cast<int**>(val)); - break; - case cmd_clearFullList: - CHECK_INIT(initialized,word); - atoms.clearFullList(); - break; - case cmd_read: - CHECK_INIT(initialized,word); - if(val)readInputFile(static_cast<char*>(val)); - else readInputFile("plumed.dat"); - break; - case cmd_readInputLine: - CHECK_INIT(initialized,word); - CHECK_NOTNULL(val,word); - readInputLine(static_cast<char*>(val)); - break; - case cmd_clear: - CHECK_INIT(initialized,word); - actionSet.clearDelete(); - break; - case cmd_getApiVersion: - CHECK_NOTNULL(val,word); - *(static_cast<int*>(val))=4; - break; - // commands which can be used only before initialization: - case cmd_init: - CHECK_NOTINIT(initialized,word); - init(); - break; - case cmd_setRealPrecision: - CHECK_NOTINIT(initialized,word); - CHECK_NOTNULL(val,word); - atoms.setRealPrecision(*static_cast<int*>(val)); - break; - case cmd_setMDLengthUnits: - CHECK_NOTINIT(initialized,word); - CHECK_NOTNULL(val,word); - atoms.MD2double(val,d); - atoms.setMDLengthUnits(d); - break; - case cmd_setMDChargeUnits: - CHECK_NOTINIT(initialized,word); - CHECK_NOTNULL(val,word); - atoms.MD2double(val,d); - atoms.setMDChargeUnits(d); - break; - case cmd_setMDMassUnits: - CHECK_NOTINIT(initialized,word); - CHECK_NOTNULL(val,word); - atoms.MD2double(val,d); - atoms.setMDMassUnits(d); - break; - case cmd_setMDEnergyUnits: - CHECK_NOTINIT(initialized,word); - CHECK_NOTNULL(val,word); - atoms.MD2double(val,d); - atoms.setMDEnergyUnits(d); - break; - case cmd_setMDTimeUnits: - CHECK_NOTINIT(initialized,word); - CHECK_NOTNULL(val,word); - atoms.MD2double(val,d); - atoms.setMDTimeUnits(d); - break; - case cmd_setNaturalUnits: + case cmd_setBox: + CHECK_INIT(initialized,word); + CHECK_NOTNULL(val,word); + atoms.setBox(val); + break; + case cmd_setPositions: + CHECK_INIT(initialized,word); + atoms.setPositions(val); + break; + case cmd_setMasses: + CHECK_INIT(initialized,word); + atoms.setMasses(val); + break; + case cmd_setCharges: + CHECK_INIT(initialized,word); + atoms.setCharges(val); + break; + case cmd_setPositionsX: + CHECK_INIT(initialized,word); + atoms.setPositions(val,0); + break; + case cmd_setPositionsY: + CHECK_INIT(initialized,word); + atoms.setPositions(val,1); + break; + case cmd_setPositionsZ: + CHECK_INIT(initialized,word); + atoms.setPositions(val,2); + break; + case cmd_setVirial: + CHECK_INIT(initialized,word); + CHECK_NOTNULL(val,word); + atoms.setVirial(val); + break; + case cmd_setEnergy: + CHECK_INIT(initialized,word); + CHECK_NOTNULL(val,word); + atoms.setEnergy(val); + break; + case cmd_setForces: + CHECK_INIT(initialized,word); + atoms.setForces(val); + break; + case cmd_setForcesX: + CHECK_INIT(initialized,word); + atoms.setForces(val,0); + break; + case cmd_setForcesY: + CHECK_INIT(initialized,word); + atoms.setForces(val,1); + break; + case cmd_setForcesZ: + CHECK_INIT(initialized,word); + atoms.setForces(val,2); + break; + case cmd_calc: + CHECK_INIT(initialized,word); + calc(); + break; + case cmd_prepareDependencies: + CHECK_INIT(initialized,word); + prepareDependencies(); + break; + case cmd_shareData: + CHECK_INIT(initialized,word); + shareData(); + break; + case cmd_prepareCalc: + CHECK_INIT(initialized,word); + prepareCalc(); + break; + case cmd_performCalc: + CHECK_INIT(initialized,word); + performCalc(); + break; + case cmd_performCalcNoUpdate: + CHECK_INIT(initialized,word); + performCalcNoUpdate(); + break; + case cmd_update: + CHECK_INIT(initialized,word); + update(); + break; + case cmd_setStep: + CHECK_INIT(initialized,word); + CHECK_NOTNULL(val,word); + step=(*static_cast<int*>(val)); + atoms.startStep(); + break; + case cmd_setStepLong: + CHECK_INIT(initialized,word); + CHECK_NOTNULL(val,word); + step=(*static_cast<long int*>(val)); + atoms.startStep(); + break; + // words used less frequently: + case cmd_setAtomsNlocal: + CHECK_INIT(initialized,word); + CHECK_NOTNULL(val,word); + atoms.setAtomsNlocal(*static_cast<int*>(val)); + break; + case cmd_setAtomsGatindex: + CHECK_INIT(initialized,word); + atoms.setAtomsGatindex(static_cast<int*>(val),false); + break; + case cmd_setAtomsFGatindex: + CHECK_INIT(initialized,word); + atoms.setAtomsGatindex(static_cast<int*>(val),true); + break; + case cmd_setAtomsContiguous: + CHECK_INIT(initialized,word); + CHECK_NOTNULL(val,word); + atoms.setAtomsContiguous(*static_cast<int*>(val)); + break; + case cmd_createFullList: + CHECK_INIT(initialized,word); + CHECK_NOTNULL(val,word); + atoms.createFullList(static_cast<int*>(val)); + break; + case cmd_getFullList: + CHECK_INIT(initialized,word); + CHECK_NOTNULL(val,word); + atoms.getFullList(static_cast<int**>(val)); + break; + case cmd_clearFullList: + CHECK_INIT(initialized,word); + atoms.clearFullList(); + break; + case cmd_read: + CHECK_INIT(initialized,word); + if(val)readInputFile(static_cast<char*>(val)); + else readInputFile("plumed.dat"); + break; + case cmd_readInputLine: + CHECK_INIT(initialized,word); + CHECK_NOTNULL(val,word); + readInputLine(static_cast<char*>(val)); + break; + case cmd_clear: + CHECK_INIT(initialized,word); + actionSet.clearDelete(); + break; + case cmd_getApiVersion: + CHECK_NOTNULL(val,word); + *(static_cast<int*>(val))=4; + break; + // commands which can be used only before initialization: + case cmd_init: + CHECK_NOTINIT(initialized,word); + init(); + break; + case cmd_setRealPrecision: + CHECK_NOTINIT(initialized,word); + CHECK_NOTNULL(val,word); + atoms.setRealPrecision(*static_cast<int*>(val)); + break; + case cmd_setMDLengthUnits: + CHECK_NOTINIT(initialized,word); + CHECK_NOTNULL(val,word); + atoms.MD2double(val,d); + atoms.setMDLengthUnits(d); + break; + case cmd_setMDChargeUnits: + CHECK_NOTINIT(initialized,word); + CHECK_NOTNULL(val,word); + atoms.MD2double(val,d); + atoms.setMDChargeUnits(d); + break; + case cmd_setMDMassUnits: + CHECK_NOTINIT(initialized,word); + CHECK_NOTNULL(val,word); + atoms.MD2double(val,d); + atoms.setMDMassUnits(d); + break; + case cmd_setMDEnergyUnits: + CHECK_NOTINIT(initialized,word); + CHECK_NOTNULL(val,word); + atoms.MD2double(val,d); + atoms.setMDEnergyUnits(d); + break; + case cmd_setMDTimeUnits: + CHECK_NOTINIT(initialized,word); + CHECK_NOTNULL(val,word); + atoms.MD2double(val,d); + atoms.setMDTimeUnits(d); + break; + case cmd_setNaturalUnits: // set the boltzman constant for MD in natural units (kb=1) // only needed in LJ codes if the MD is passing temperatures to plumed (so, not yet...) // use as cmd("setNaturalUnits") - CHECK_NOTINIT(initialized,word); - atoms.setMDNaturalUnits(true); - break; - case cmd_setNoVirial: - CHECK_NOTINIT(initialized,word); - novirial=true; - break; - case cmd_setPlumedDat: - CHECK_NOTINIT(initialized,word); - CHECK_NOTNULL(val,word); - plumedDat=static_cast<char*>(val); - break; - case cmd_setMPIComm: - CHECK_NOTINIT(initialized,word); - comm.Set_comm(val); - atoms.setDomainDecomposition(comm); - break; - case cmd_setMPIFComm: - CHECK_NOTINIT(initialized,word); - comm.Set_fcomm(val); - atoms.setDomainDecomposition(comm); - break; - case cmd_setMPImultiSimComm: - CHECK_NOTINIT(initialized,word); - multi_sim_comm.Set_comm(val); - break; - case cmd_setNatoms: - CHECK_NOTINIT(initialized,word); - CHECK_NOTNULL(val,word); - atoms.setNatoms(*static_cast<int*>(val)); - break; - case cmd_setTimestep: - CHECK_NOTINIT(initialized,word); - CHECK_NOTNULL(val,word); - atoms.setTimeStep(val); - break; - /* ADDED WITH API==2 */ - case cmd_setKbT: - CHECK_NOTINIT(initialized,word); - CHECK_NOTNULL(val,word); - atoms.setKbT(val); - break; - /* ADDED WITH API==3 */ - case cmd_setRestart: - CHECK_NOTINIT(initialized,word); - CHECK_NOTNULL(val,word); - if(*static_cast<int*>(val)!=0) restart=true; - break; - /* ADDED WITH API==4 */ - case cmd_doCheckPoint: - CHECK_INIT(initialized,word); - CHECK_NOTNULL(val,word); - doCheckPoint = false; - if(*static_cast<int*>(val)!=0) doCheckPoint = true; - break; - /* STOP API */ - case cmd_setMDEngine: - CHECK_NOTINIT(initialized,word); - CHECK_NOTNULL(val,word); - MDEngine=static_cast<char*>(val); - break; - case cmd_setLog: - CHECK_NOTINIT(initialized,word); - log.link(static_cast<FILE*>(val)); - break; - case cmd_setLogFile: - CHECK_NOTINIT(initialized,word); - CHECK_NOTNULL(val,word); - log.open(static_cast<char*>(val)); - break; - // other commands that should be used after initialization: - case cmd_setStopFlag: - CHECK_INIT(initialized,word); - CHECK_NOTNULL(val,word); - stopFlag=static_cast<int*>(val); - break; - case cmd_getExchangesFlag: - CHECK_INIT(initialized,word); - CHECK_NOTNULL(val,word); - exchangePatterns.getFlag((*static_cast<int*>(val))); - break; - case cmd_setExchangesSeed: - CHECK_INIT(initialized,word); - CHECK_NOTNULL(val,word); - exchangePatterns.setSeed((*static_cast<int*>(val))); - break; - case cmd_setNumberOfReplicas: - CHECK_INIT(initialized,word); - CHECK_NOTNULL(val,word); - exchangePatterns.setNofR((*static_cast<int*>(val))); - break; - case cmd_getExchangesList: - CHECK_INIT(initialized,word); - CHECK_NOTNULL(val,word); - exchangePatterns.getList((static_cast<int*>(val))); - break; - case cmd_runFinalJobs: - CHECK_INIT(initialized,word); - runJobsAtEndOfCalculation(); - break; - case cmd_isEnergyNeeded: - CHECK_INIT(initialized,word); - CHECK_NOTNULL(val,word); - if(atoms.isEnergyNeeded()) *(static_cast<int*>(val))=1; - else *(static_cast<int*>(val))=0; - break; - case cmd_getBias: - CHECK_INIT(initialized,word); - CHECK_NOTNULL(val,word); - atoms.double2MD(getBias()/(atoms.getMDUnits().getEnergy()/atoms.getUnits().getEnergy()),val); - break; - case cmd_checkAction: - CHECK_NOTNULL(val,word); - plumed_assert(nw==2); - *(static_cast<int*>(val))=(actionRegister().check(words[1]) ? 1:0); - break; - case cmd_GREX: - if(!grex) grex=new GREX(*this); - plumed_massert(grex,"error allocating grex"); - { - std::string kk=words[1]; - for(unsigned i=2;i<words.size();i++) kk+=" "+words[i]; - grex->cmd(kk.c_str(),val); - } - break; - case cmd_CLTool: - CHECK_NOTINIT(initialized,word); - if(!cltool) cltool=new CLToolMain; - { - std::string kk=words[1]; - for(unsigned i=2;i<words.size();i++) kk+=" "+words[i]; - cltool->cmd(kk.c_str(),val); - } - break; - default: - plumed_merror("cannot interpret cmd(\"" + word + "\"). check plumed developers manual to see the available commands."); - break; + CHECK_NOTINIT(initialized,word); + atoms.setMDNaturalUnits(true); + break; + case cmd_setNoVirial: + CHECK_NOTINIT(initialized,word); + novirial=true; + break; + case cmd_setPlumedDat: + CHECK_NOTINIT(initialized,word); + CHECK_NOTNULL(val,word); + plumedDat=static_cast<char*>(val); + break; + case cmd_setMPIComm: + CHECK_NOTINIT(initialized,word); + comm.Set_comm(val); + atoms.setDomainDecomposition(comm); + break; + case cmd_setMPIFComm: + CHECK_NOTINIT(initialized,word); + comm.Set_fcomm(val); + atoms.setDomainDecomposition(comm); + break; + case cmd_setMPImultiSimComm: + CHECK_NOTINIT(initialized,word); + multi_sim_comm.Set_comm(val); + break; + case cmd_setNatoms: + CHECK_NOTINIT(initialized,word); + CHECK_NOTNULL(val,word); + atoms.setNatoms(*static_cast<int*>(val)); + break; + case cmd_setTimestep: + CHECK_NOTINIT(initialized,word); + CHECK_NOTNULL(val,word); + atoms.setTimeStep(val); + break; + /* ADDED WITH API==2 */ + case cmd_setKbT: + CHECK_NOTINIT(initialized,word); + CHECK_NOTNULL(val,word); + atoms.setKbT(val); + break; + /* ADDED WITH API==3 */ + case cmd_setRestart: + CHECK_NOTINIT(initialized,word); + CHECK_NOTNULL(val,word); + if(*static_cast<int*>(val)!=0) restart=true; + break; + /* ADDED WITH API==4 */ + case cmd_doCheckPoint: + CHECK_INIT(initialized,word); + CHECK_NOTNULL(val,word); + doCheckPoint = false; + if(*static_cast<int*>(val)!=0) doCheckPoint = true; + break; + /* STOP API */ + case cmd_setMDEngine: + CHECK_NOTINIT(initialized,word); + CHECK_NOTNULL(val,word); + MDEngine=static_cast<char*>(val); + break; + case cmd_setLog: + CHECK_NOTINIT(initialized,word); + log.link(static_cast<FILE*>(val)); + break; + case cmd_setLogFile: + CHECK_NOTINIT(initialized,word); + CHECK_NOTNULL(val,word); + log.open(static_cast<char*>(val)); + break; + // other commands that should be used after initialization: + case cmd_setStopFlag: + CHECK_INIT(initialized,word); + CHECK_NOTNULL(val,word); + stopFlag=static_cast<int*>(val); + break; + case cmd_getExchangesFlag: + CHECK_INIT(initialized,word); + CHECK_NOTNULL(val,word); + exchangePatterns.getFlag((*static_cast<int*>(val))); + break; + case cmd_setExchangesSeed: + CHECK_INIT(initialized,word); + CHECK_NOTNULL(val,word); + exchangePatterns.setSeed((*static_cast<int*>(val))); + break; + case cmd_setNumberOfReplicas: + CHECK_INIT(initialized,word); + CHECK_NOTNULL(val,word); + exchangePatterns.setNofR((*static_cast<int*>(val))); + break; + case cmd_getExchangesList: + CHECK_INIT(initialized,word); + CHECK_NOTNULL(val,word); + exchangePatterns.getList((static_cast<int*>(val))); + break; + case cmd_runFinalJobs: + CHECK_INIT(initialized,word); + runJobsAtEndOfCalculation(); + break; + case cmd_isEnergyNeeded: + CHECK_INIT(initialized,word); + CHECK_NOTNULL(val,word); + if(atoms.isEnergyNeeded()) *(static_cast<int*>(val))=1; + else *(static_cast<int*>(val))=0; + break; + case cmd_getBias: + CHECK_INIT(initialized,word); + CHECK_NOTNULL(val,word); + atoms.double2MD(getBias()/(atoms.getMDUnits().getEnergy()/atoms.getUnits().getEnergy()),val); + break; + case cmd_checkAction: + CHECK_NOTNULL(val,word); + plumed_assert(nw==2); + *(static_cast<int*>(val))=(actionRegister().check(words[1]) ? 1:0); + break; + case cmd_GREX: + if(!grex) grex=new GREX(*this); + plumed_massert(grex,"error allocating grex"); + { + std::string kk=words[1]; + for(unsigned i=2; i<words.size(); i++) kk+=" "+words[i]; + grex->cmd(kk.c_str(),val); + } + break; + case cmd_CLTool: + CHECK_NOTINIT(initialized,word); + if(!cltool) cltool=new CLToolMain; + { + std::string kk=words[1]; + for(unsigned i=2; i<words.size(); i++) kk+=" "+words[i]; + cltool->cmd(kk.c_str(),val); + } + break; + default: + plumed_merror("cannot interpret cmd(\"" + word + "\"). check plumed developers manual to see the available commands."); + break; } } stopwatch.pause(); @@ -465,7 +465,7 @@ void PlumedMain::cmd(const std::string & word,void*val){ //////////////////////////////////////////////////////////////////////// -void PlumedMain::init(){ +void PlumedMain::init() { // check that initialization just happens once initialized=true; atoms.init(); @@ -486,7 +486,7 @@ void PlumedMain::init(){ log.printf("Number of atoms: %d\n",atoms.getNatoms()); if(grex) log.printf("GROMACS-like replica exchange is on\n"); log.printf("File suffix: %s\n",getSuffix().c_str()); - if(plumedDat.length()>0){ + if(plumedDat.length()>0) { readInputFile(plumedDat); plumedDat=""; } @@ -504,7 +504,7 @@ void PlumedMain::init(){ log<<"Finished setup\n"; } -void PlumedMain::readInputFile(std::string str){ +void PlumedMain::readInputFile(std::string str) { plumed_assert(initialized); log.printf("FILE: %s\n",str.c_str()); IFile ifile; @@ -519,34 +519,34 @@ void PlumedMain::readInputFile(std::string str){ pilots=actionSet.select<ActionPilot*>(); } -void PlumedMain::readInputLine(const std::string & str){ +void PlumedMain::readInputLine(const std::string & str) { plumed_assert(initialized); if(str.empty()) return; std::vector<std::string> words=Tools::getWords(str); citations.clear(); readInputWords(words); - if(!citations.empty()){ + if(!citations.empty()) { log<<"Relevant bibliography:\n"; log<<citations; log<<"Please read and cite where appropriate!\n"; } } -void PlumedMain::readInputWords(const std::vector<std::string> & words){ +void PlumedMain::readInputWords(const std::vector<std::string> & words) { plumed_assert(initialized); if(words.empty())return; else if(words[0]=="ENDPLUMED") return; - else if(words[0]=="_SET_SUFFIX"){ + else if(words[0]=="_SET_SUFFIX") { plumed_assert(words.size()==2); setSuffix(words[1]); } else { std::vector<std::string> interpreted(words); Tools::interpretLabel(interpreted); Action* action=actionRegister().create(ActionOptions(*this,interpreted)); - if(!action){ + if(!action) { log<<"ERROR\n"; log<<"I cannot understand line:"; - for(unsigned i=0;i<interpreted.size();++i) log<<" "<<interpreted[i]; + for(unsigned i=0; i<interpreted.size(); ++i) log<<" "<<interpreted[i]; log<<"\n"; log.flush(); plumed_merror("I cannot understand line " + interpreted[0] + " " + interpreted[1]); @@ -560,20 +560,20 @@ void PlumedMain::readInputWords(const std::vector<std::string> & words){ //////////////////////////////////////////////////////////////////////// -void PlumedMain::exit(int c){ +void PlumedMain::exit(int c) { comm.Abort(c); } -Log& PlumedMain::getLog(){ +Log& PlumedMain::getLog() { return log; } -void PlumedMain::calc(){ +void PlumedMain::calc() { prepareCalc(); performCalc(); } -void PlumedMain::prepareCalc(){ +void PlumedMain::prepareCalc() { prepareDependencies(); shareData(); } @@ -582,7 +582,7 @@ void PlumedMain::prepareCalc(){ // here we have the main steps in "calc()" // they can be called individually, but the standard thing is to // traverse them in this order: -void PlumedMain::prepareDependencies(){ +void PlumedMain::prepareDependencies() { stopwatch.start("1 Prepare dependencies"); @@ -593,24 +593,24 @@ void PlumedMain::prepareDependencies(){ // which can be dynamically changed). // First switch off all actions - for(const auto & p : actionSet){ - p->deactivate(); - //I think this is already done inside deactivate - //(*p)->clearOptions(); + for(const auto & p : actionSet) { + p->deactivate(); + //I think this is already done inside deactivate + //(*p)->clearOptions(); } // for optimization, an "active" flag remains false if no action at all is active active=false; - for(unsigned i=0;i<pilots.size();++i){ - if(pilots[i]->onStep()){ + for(unsigned i=0; i<pilots.size(); ++i) { + if(pilots[i]->onStep()) { pilots[i]->activate(); active=true; - } + } }; // also, if one of them is the total energy, tell to atoms that energy should be collected - for(const auto & p : actionSet){ - if(p->isActive()){ + for(const auto & p : actionSet) { + if(p->isActive()) { if(p->checkNeedsGradients()) p->setOption("GRADIENTS"); } } @@ -618,7 +618,7 @@ void PlumedMain::prepareDependencies(){ stopwatch.stop("1 Prepare dependencies"); } -void PlumedMain::shareData(){ +void PlumedMain::shareData() { // atom positions are shared (but only if there is something to do) if(!active)return; stopwatch.start("2 Sharing data"); @@ -626,27 +626,27 @@ void PlumedMain::shareData(){ stopwatch.stop("2 Sharing data"); } -void PlumedMain::performCalcNoUpdate(){ +void PlumedMain::performCalcNoUpdate() { waitData(); justCalculate(); backwardPropagate(); } -void PlumedMain::performCalc(){ +void PlumedMain::performCalc() { waitData(); justCalculate(); backwardPropagate(); update(); } -void PlumedMain::waitData(){ +void PlumedMain::waitData() { if(!active)return; stopwatch.start("3 Waiting for data"); if(atoms.getNatoms()>0) atoms.wait(); stopwatch.stop("3 Waiting for data"); } -void PlumedMain::justCalculate(){ +void PlumedMain::justCalculate() { if(!active)return; stopwatch.start("4 Calculating (forward loop)"); bias=0.0; @@ -654,10 +654,10 @@ void PlumedMain::justCalculate(){ int iaction=0; // calculate the active actions in order (assuming *backward* dependence) - for(const auto & p : actionSet){ - if(p->isActive()){ + for(const auto & p : actionSet) { + if(p->isActive()) { std::string actionNumberLabel; - if(detailedTimers){ + if(detailedTimers) { Tools::convert(iaction,actionNumberLabel); actionNumberLabel="4A "+actionNumberLabel+" "+p->getLabel(); stopwatch.start(actionNumberLabel); @@ -674,12 +674,12 @@ void PlumedMain::justCalculate(){ } if(p->checkNumericalDerivatives()) p->calculateNumericalDerivatives(); else p->calculate(); - // This retrieves components called bias + // This retrieves components called bias if(av) bias+=av->getOutputQuantity("bias"); if(av) work+=av->getOutputQuantity("work"); - if(av)av->setGradientsIfNeeded(); + if(av)av->setGradientsIfNeeded(); ActionWithVirtualAtom*avv=dynamic_cast<ActionWithVirtualAtom*>(p); - if(avv)avv->setGradientsIfNeeded(); + if(avv)avv->setGradientsIfNeeded(); if(detailedTimers) stopwatch.stop(actionNumberLabel); } iaction++; @@ -687,22 +687,22 @@ void PlumedMain::justCalculate(){ stopwatch.stop("4 Calculating (forward loop)"); } -void PlumedMain::justApply(){ +void PlumedMain::justApply() { backwardPropagate(); update(); } - -void PlumedMain::backwardPropagate(){ + +void PlumedMain::backwardPropagate() { if(!active)return; int iaction=0; stopwatch.start("5 Applying (backward loop)"); // apply them in reverse order - for(auto pp=actionSet.rbegin();pp!=actionSet.rend();++pp){ + for(auto pp=actionSet.rbegin(); pp!=actionSet.rend(); ++pp) { const auto & p(*pp); - if(p->isActive()){ + if(p->isActive()) { std::string actionNumberLabel; - if(detailedTimers){ + if(detailedTimers) { Tools::convert(iaction,actionNumberLabel); actionNumberLabel="5A "+actionNumberLabel+" "+p->getLabel(); stopwatch.start(actionNumberLabel); @@ -725,28 +725,28 @@ void PlumedMain::backwardPropagate(){ stopwatch.stop("5 Applying (backward loop)"); } -void PlumedMain::update(){ +void PlumedMain::update() { if(!active)return; stopwatch.start("6 Update"); // update step (for statistics, etc) updateFlags.push(true); - for(const auto & p : actionSet){ + for(const auto & p : actionSet) { p->beforeUpdate(); if(p->isActive() && p->checkUpdate() && updateFlagsTop()) p->update(); } while(!updateFlags.empty()) updateFlags.pop(); if(!updateFlags.empty()) plumed_merror("non matching changes in the update flags"); // Check that no action has told the calculation to stop - if(stopNow){ - if(stopFlag) (*stopFlag)=1; - else plumed_merror("your md code cannot handle plumed stop events - add a call to plumed.comm(stopFlag,stopCondition)"); - } + if(stopNow) { + if(stopFlag) (*stopFlag)=1; + else plumed_merror("your md code cannot handle plumed stop events - add a call to plumed.comm(stopFlag,stopCondition)"); + } // flush by default every 10000 steps // hopefully will not affect performance // also if receive checkpointing signal - if(step%10000==0||doCheckPoint){ + if(step%10000==0||doCheckPoint) { fflush(); log.flush(); for(const auto & p : actionSet) p->fflush(); @@ -754,49 +754,49 @@ void PlumedMain::update(){ stopwatch.stop("6 Update"); } -void PlumedMain::load(const std::string& ss){ - if(DLLoader::installed()){ - string s=ss; - size_t n=s.find_last_of("."); - string extension=""; - string base=s; - if(n!=std::string::npos && n<s.length()-1) extension=s.substr(n+1); - if(n!=std::string::npos && n<s.length()) base=s.substr(0,n); - if(extension=="cpp"){ +void PlumedMain::load(const std::string& ss) { + if(DLLoader::installed()) { + string s=ss; + size_t n=s.find_last_of("."); + string extension=""; + string base=s; + if(n!=std::string::npos && n<s.length()-1) extension=s.substr(n+1); + if(n!=std::string::npos && n<s.length()) base=s.substr(0,n); + if(extension=="cpp") { // full path command, including environment setup // this will work even if plumed is not in the execution path or if it has been // installed with a name different from "plumed" - string cmd=config::getEnvCommand()+" \""+config::getPlumedRoot()+"\"/scripts/mklib.sh "+s; - log<<"Executing: "<<cmd; - if(comm.Get_size()>0) log<<" (only on master node)"; - log<<"\n"; - if(comm.Get_rank()==0) system(cmd.c_str()); - comm.Barrier(); - base="./"+base; - } - s=base+"."+config::getSoExt(); - void *p=dlloader.load(s); - if(!p){ - const std::string error_msg="I cannot load library " + ss + " " + dlloader.error(); - log<<"ERROR\n"; - log<<error_msg<<"\n"; - plumed_merror(error_msg); - } - log<<"Loading shared library "<<s.c_str()<<"\n"; - log<<"Here is the new list of available actions\n"; - log<<actionRegister(); + string cmd=config::getEnvCommand()+" \""+config::getPlumedRoot()+"\"/scripts/mklib.sh "+s; + log<<"Executing: "<<cmd; + if(comm.Get_size()>0) log<<" (only on master node)"; + log<<"\n"; + if(comm.Get_rank()==0) system(cmd.c_str()); + comm.Barrier(); + base="./"+base; + } + s=base+"."+config::getSoExt(); + void *p=dlloader.load(s); + if(!p) { + const std::string error_msg="I cannot load library " + ss + " " + dlloader.error(); + log<<"ERROR\n"; + log<<error_msg<<"\n"; + plumed_merror(error_msg); + } + log<<"Loading shared library "<<s.c_str()<<"\n"; + log<<"Here is the new list of available actions\n"; + log<<actionRegister(); } else plumed_merror("loading not enabled, please recompile with -D__PLUMED_HAS_DLOPEN"); } -double PlumedMain::getBias() const{ +double PlumedMain::getBias() const { return bias; } -double PlumedMain::getWork() const{ +double PlumedMain::getWork() const { return work; } -FILE* PlumedMain::fopen(const char *path, const char *mode){ +FILE* PlumedMain::fopen(const char *path, const char *mode) { std::string mmode(mode); std::string ppath(path); std::string suffix(getSuffix()); @@ -807,37 +807,37 @@ FILE* PlumedMain::fopen(const char *path, const char *mode){ return fp; } -int PlumedMain::fclose(FILE*fp){ +int PlumedMain::fclose(FILE*fp) { return std::fclose(fp); } -std::string PlumedMain::cite(const std::string&item){ +std::string PlumedMain::cite(const std::string&item) { return citations.cite(item); } -void PlumedMain::fflush(){ - for(const auto & p : files){ +void PlumedMain::fflush() { + for(const auto & p : files) { p->flush(); } } -void PlumedMain::insertFile(FileBase&f){ +void PlumedMain::insertFile(FileBase&f) { files.insert(&f); } -void PlumedMain::eraseFile(FileBase&f){ +void PlumedMain::eraseFile(FileBase&f) { files.erase(&f); } -void PlumedMain::stop(){ +void PlumedMain::stop() { stopNow=true; } -void PlumedMain::runJobsAtEndOfCalculation(){ - for(const auto & p : actionSet){ - p->runFinalJobs(); +void PlumedMain::runJobsAtEndOfCalculation() { + for(const auto & p : actionSet) { + p->runFinalJobs(); } -} +} } diff --git a/src/core/PlumedMain.h b/src/core/PlumedMain.h index ced8d15c9..ad2662844 100644 --- a/src/core/PlumedMain.h +++ b/src/core/PlumedMain.h @@ -171,104 +171,104 @@ public: PlumedMain(); // this is to access to WithCmd versions of cmd (allowing overloading of a virtual method) using WithCmd::cmd; -/** - cmd method, accessible with standard Plumed.h interface. - \param key The name of the command to be executed. - \param val The argument of the command to be executed. - It is called as plumed_cmd() or as PLMD::Plumed::cmd() - It is the interpreter for plumed commands. It basically contains the definition of the plumed interface. - If you want to add a new functionality to the interface between plumed - and an MD engine, this is the right place - Notice that this interface should always keep retro-compatibility -*/ + /** + cmd method, accessible with standard Plumed.h interface. + \param key The name of the command to be executed. + \param val The argument of the command to be executed. + It is called as plumed_cmd() or as PLMD::Plumed::cmd() + It is the interpreter for plumed commands. It basically contains the definition of the plumed interface. + If you want to add a new functionality to the interface between plumed + and an MD engine, this is the right place + Notice that this interface should always keep retro-compatibility + */ void cmd(const std::string&key,void*val=NULL); ~PlumedMain(); -/** - Read an input file. - \param str name of the file -*/ + /** + Read an input file. + \param str name of the file + */ void readInputFile(std::string str); -/** - Read an input string. - \param str name of the string -*/ + /** + Read an input string. + \param str name of the string + */ void readInputWords(const std::vector<std::string> & str); -/** - Read an input string. - \param str name of the string - At variance with readInputWords(), this is splitting the string into words -*/ + /** + Read an input string. + \param str name of the string + At variance with readInputWords(), this is splitting the string into words + */ void readInputLine(const std::string & str); -/** - Initialize the object. - Should be called once. -*/ + /** + Initialize the object. + Should be called once. + */ void init(); -/** - Prepare the calculation. - Here it is checked which are the active Actions and communication of the relevant atoms is initiated. - Shortcut for prepareDependencies() + shareData() -*/ + /** + Prepare the calculation. + Here it is checked which are the active Actions and communication of the relevant atoms is initiated. + Shortcut for prepareDependencies() + shareData() + */ void prepareCalc(); -/** - Prepare the list of active Actions and needed atoms. - Scan the Actions to see which are active and which are not, so as to prepare a list of - the atoms needed at this step. -*/ + /** + Prepare the list of active Actions and needed atoms. + Scan the Actions to see which are active and which are not, so as to prepare a list of + the atoms needed at this step. + */ void prepareDependencies(); -/** - Share the needed atoms. - In asynchronous implementations, this method sends the required atoms to all the plumed processes, - without waiting for the communication to complete. -*/ + /** + Share the needed atoms. + In asynchronous implementations, this method sends the required atoms to all the plumed processes, + without waiting for the communication to complete. + */ void shareData(); -/** - Perform the calculation. - Shortcut for waitData() + justCalculate() + justApply(). - Equivalently: waitData() + justCalculate() + backwardPropagate() + update(). -*/ + /** + Perform the calculation. + Shortcut for waitData() + justCalculate() + justApply(). + Equivalently: waitData() + justCalculate() + backwardPropagate() + update(). + */ void performCalc(); -/** - Perform the calculation without update() - Shortcut for: waitData() + justCalculate() + backwardPropagate() -*/ + /** + Perform the calculation without update() + Shortcut for: waitData() + justCalculate() + backwardPropagate() + */ void performCalcNoUpdate(); -/** - Complete PLUMED calculation. - Shortcut for prepareCalc() + performCalc() -*/ + /** + Complete PLUMED calculation. + Shortcut for prepareCalc() + performCalc() + */ void calc(); -/** - Scatters the needed atoms. - In asynchronous implementations, this method waits for the communications started in shareData() - to be completed. Otherwise, just send around needed atoms. -*/ + /** + Scatters the needed atoms. + In asynchronous implementations, this method waits for the communications started in shareData() + to be completed. Otherwise, just send around needed atoms. + */ void waitData(); -/** - Perform the forward loop on active actions. -*/ + /** + Perform the forward loop on active actions. + */ void justCalculate(); -/** - Backward propagate and update. - Shortcut for backwardPropagate() + update() - I leave it here for backward compatibility -*/ + /** + Backward propagate and update. + Shortcut for backwardPropagate() + update() + I leave it here for backward compatibility + */ void justApply(); -/** - Perform the backward loop on active actions. - Needed to apply the forces back. -*/ + /** + Perform the backward loop on active actions. + Needed to apply the forces back. + */ void backwardPropagate(); -/** - Call the update() method. -*/ + /** + Call the update() method. + */ void update(); -/** - If there are calculations that need to be done at the very end of the calculations this - makes sures they are done -*/ + /** + If there are calculations that need to be done at the very end of the calculations this + makes sures they are done + */ void runJobsAtEndOfCalculation(); /// Reference to atoms object Atoms& getAtoms(); @@ -277,7 +277,7 @@ public: /// Referenge to the log stream Log & getLog(); /// Return the number of the step - long int getStep()const{return step;} + long int getStep()const {return step;} /// Stop the run void exit(int c=0); /// Load a shared library @@ -305,8 +305,8 @@ public: /// Check if restarting bool getRestart()const; /// Set restart flag - void setRestart(bool f){restart=f;} -/// Check if checkpointing + void setRestart(bool f) {restart=f;} +/// Check if checkpointing bool getCPT()const; /// Set exchangeStep flag void setExchangeStep(bool f); @@ -322,7 +322,7 @@ public: void resetActive(bool active); /// Access to exchange patterns - ExchangePatterns& getExchangePatterns(){return exchangePatterns;} + ExchangePatterns& getExchangePatterns() {return exchangePatterns;} /// Push a state to update flags void updateFlagsPush(bool); @@ -336,62 +336,62 @@ public: // FAST INLINE METHODS: inline -const ActionSet & PlumedMain::getActionSet()const{ +const ActionSet & PlumedMain::getActionSet()const { return actionSet; } inline -Atoms& PlumedMain::getAtoms(){ +Atoms& PlumedMain::getAtoms() { return atoms; } inline -const std::string & PlumedMain::getSuffix()const{ +const std::string & PlumedMain::getSuffix()const { return suffix; } inline -void PlumedMain::setSuffix(const std::string&s){ +void PlumedMain::setSuffix(const std::string&s) { suffix=s; } inline -bool PlumedMain::getRestart()const{ +bool PlumedMain::getRestart()const { return restart; } inline -bool PlumedMain::getCPT()const{ +bool PlumedMain::getCPT()const { return doCheckPoint; } inline -void PlumedMain::setExchangeStep(bool s){ +void PlumedMain::setExchangeStep(bool s) { exchangeStep=s; } inline -bool PlumedMain::getExchangeStep()const{ +bool PlumedMain::getExchangeStep()const { return exchangeStep; } inline -void PlumedMain::resetActive(bool active){ +void PlumedMain::resetActive(bool active) { this->active=active; } inline -void PlumedMain::updateFlagsPush(bool on){ +void PlumedMain::updateFlagsPush(bool on) { updateFlags.push(on); } inline -void PlumedMain::updateFlagsPop(){ +void PlumedMain::updateFlagsPop() { updateFlags.pop(); } inline -bool PlumedMain::updateFlagsTop(){ +bool PlumedMain::updateFlagsTop() { return updateFlags.top(); } diff --git a/src/core/PlumedMainInitializer.cpp b/src/core/PlumedMainInitializer.cpp index 20244e257..b7fc8e3e4 100644 --- a/src/core/PlumedMainInitializer.cpp +++ b/src/core/PlumedMainInitializer.cpp @@ -43,16 +43,16 @@ typedef struct { /* These functions should be accessible from C, since they might be statically used from Plumed.c (for static binding) */ -extern "C" void*plumedmain_create(){ +extern "C" void*plumedmain_create() { return new PLMD::PlumedMain; } -extern "C" void plumedmain_cmd(void*plumed,const char*key,const void*val){ +extern "C" void plumedmain_cmd(void*plumed,const char*key,const void*val) { plumed_massert(plumed,"trying to use a plumed object which is not initialized"); static_cast<PLMD::PlumedMain*>(plumed)->cmd(key,val); } -extern "C" void plumedmain_finalize(void*plumed){ +extern "C" void plumedmain_finalize(void*plumed) { plumed_massert(plumed,"trying to deallocate a plumed object which is not initialized"); delete static_cast<PLMD::PlumedMain*>(plumed); } @@ -60,16 +60,16 @@ extern "C" void plumedmain_finalize(void*plumed){ /* This refers to a function implemented in Plumed.c */ extern "C" plumed_plumedmain_function_holder* plumed_kernel_register(const plumed_plumedmain_function_holder*); -namespace PLMD{ +namespace PLMD { /// Static object which registers Plumed. /// This is a static object which, during its construction at startup, /// registers the pointers to plumedmain_create, plumedmain_cmd and plumedmain_finalize /// to the plumed_kernel_register function -static class PlumedMainInitializer{ - public: - PlumedMainInitializer(){ - plumed_plumedmain_function_holder fh={plumedmain_create,plumedmain_cmd,plumedmain_finalize}; +static class PlumedMainInitializer { +public: + PlumedMainInitializer() { + plumed_plumedmain_function_holder fh= {plumedmain_create,plumedmain_cmd,plumedmain_finalize}; plumed_kernel_register(&fh); } } RegisterMe; diff --git a/src/core/SetupMolInfo.cpp b/src/core/SetupMolInfo.cpp index af6a4d513..662ddfb1c 100644 --- a/src/core/SetupMolInfo.cpp +++ b/src/core/SetupMolInfo.cpp @@ -38,24 +38,24 @@ compilation will exclude it from plumed. */ -void SetupMolInfo::registerKeywords( Keywords& keys ){ +void SetupMolInfo::registerKeywords( Keywords& keys ) { ActionSetup::registerKeywords(keys); keys.add("compulsory","STRUCTURE","a file in pdb format containing a reference structure. " - "This is used to defines the atoms in the various residues, chains, etc . " - "For more details on the PDB file format visit http://www.wwpdb.org/docs.html"); + "This is used to defines the atoms in the various residues, chains, etc . " + "For more details on the PDB file format visit http://www.wwpdb.org/docs.html"); keys.add("compulsory","MOLTYPE","protein","what kind of molecule is contained in the pdb file"); keys.add("atoms","CHAIN","(for masochists ( mostly Davide Branduardi ) ) The atoms involved in each of the chains of interest in the structure."); } -SetupMolInfo::~SetupMolInfo(){ +SetupMolInfo::~SetupMolInfo() { delete &pdb; } SetupMolInfo::SetupMolInfo( const ActionOptions&ao ): -Action(ao), -ActionSetup(ao), -ActionAtomistic(ao), -pdb(*new(PDB)) + Action(ao), + ActionSetup(ao), + ActionAtomistic(ao), + pdb(*new(PDB)) { // Read what is contained in the pdb file parse("MOLTYPE",mytype); @@ -65,126 +65,126 @@ pdb(*new(PDB)) std::vector<AtomNumber> backbone; parseAtomList("CHAIN",backbone); - if( read_backbone.size()==0 ){ - for(unsigned i=1;;++i){ - parseAtomList("CHAIN",i,backbone); - if( backbone.size()==0 ) break; - read_backbone.push_back(backbone); - backbone.resize(0); - } - } else { + if( read_backbone.size()==0 ) { + for(unsigned i=1;; ++i) { + parseAtomList("CHAIN",i,backbone); + if( backbone.size()==0 ) break; read_backbone.push_back(backbone); + backbone.resize(0); + } + } else { + read_backbone.push_back(backbone); } - if( read_backbone.size()==0 ){ + if( read_backbone.size()==0 ) { std::string reference; parse("STRUCTURE",reference); if( ! pdb.read(reference,plumed.getAtoms().usingNaturalUnits(),0.1/plumed.getAtoms().getUnits().getLength()))plumed_merror("missing input file " + reference ); std::vector<std::string> chains; pdb.getChainNames( chains ); log.printf(" pdb file named %s contains %u chains \n",reference.c_str(), static_cast<unsigned>(chains.size())); - for(unsigned i=0;i<chains.size();++i){ - unsigned start,end; std::string errmsg; - pdb.getResidueRange( chains[i], start, end, errmsg ); - if( errmsg.length()!=0 ) error( errmsg ); - AtomNumber astart,aend; - pdb.getAtomRange( chains[i], astart, aend, errmsg ); - if( errmsg.length()!=0 ) error( errmsg ); - log.printf(" chain named %s contains residues %u to %u and atoms %u to %u \n",chains[i].c_str(),start,end,astart.serial(),aend.serial()); + for(unsigned i=0; i<chains.size(); ++i) { + unsigned start,end; std::string errmsg; + pdb.getResidueRange( chains[i], start, end, errmsg ); + if( errmsg.length()!=0 ) error( errmsg ); + AtomNumber astart,aend; + pdb.getAtomRange( chains[i], astart, aend, errmsg ); + if( errmsg.length()!=0 ) error( errmsg ); + log.printf(" chain named %s contains residues %u to %u and atoms %u to %u \n",chains[i].c_str(),start,end,astart.serial(),aend.serial()); } } } -void SetupMolInfo::getBackbone( std::vector<std::string>& restrings, const std::string& fortype, std::vector< std::vector<AtomNumber> >& backbone ){ +void SetupMolInfo::getBackbone( std::vector<std::string>& restrings, const std::string& fortype, std::vector< std::vector<AtomNumber> >& backbone ) { if( fortype!=mytype ) error("cannot calculate a variable designed for " + fortype + " molecules for molecule type " + mytype ); if( MolDataClass::numberOfAtomsPerResidueInBackbone( mytype )==0 ) error("backbone is not defined for molecule type " + mytype ); - if( read_backbone.size()!=0 ){ - if( restrings.size()!=1 ) error("cannot interpret anything other than all for residues when using CHAIN keywords"); - if( restrings[0]!="all" ) error("cannot interpret anything other than all for residues when using CHAIN keywords"); - backbone.resize( read_backbone.size() ); - for(unsigned i=0;i<read_backbone.size();++i){ - backbone[i].resize( read_backbone[i].size() ); - for(unsigned j=0;j<read_backbone[i].size();++j) backbone[i][j]=read_backbone[i][j]; - } + if( read_backbone.size()!=0 ) { + if( restrings.size()!=1 ) error("cannot interpret anything other than all for residues when using CHAIN keywords"); + if( restrings[0]!="all" ) error("cannot interpret anything other than all for residues when using CHAIN keywords"); + backbone.resize( read_backbone.size() ); + for(unsigned i=0; i<read_backbone.size(); ++i) { + backbone[i].resize( read_backbone[i].size() ); + for(unsigned j=0; j<read_backbone[i].size(); ++j) backbone[i][j]=read_backbone[i][j]; + } } else { - bool useter=false; // This is used to deal with terminal groups in WHOLEMOLECULES - if( restrings.size()==1 ){ - useter=( restrings[0].find("ter")!=std::string::npos ); - if( restrings[0].find("all")!=std::string::npos ){ - std::vector<std::string> chains; pdb.getChainNames( chains ); - for(unsigned i=0;i<chains.size();++i){ - unsigned r_start, r_end; std::string errmsg, mm, nn; - pdb.getResidueRange( chains[i], r_start, r_end, errmsg ); - if( !useter ){ - std::string resname = pdb.getResidueName( r_start ); - if( MolDataClass::isTerminalGroup( mytype, resname ) ) r_start++; - resname = pdb.getResidueName( r_end ); - if( MolDataClass::isTerminalGroup( mytype, resname ) ) r_end--; - } - Tools::convert(r_start,mm); Tools::convert(r_end,nn); - if(i==0) restrings[0] = mm + "-" + nn; - else restrings.push_back( mm + "-" + nn ); - } + bool useter=false; // This is used to deal with terminal groups in WHOLEMOLECULES + if( restrings.size()==1 ) { + useter=( restrings[0].find("ter")!=std::string::npos ); + if( restrings[0].find("all")!=std::string::npos ) { + std::vector<std::string> chains; pdb.getChainNames( chains ); + for(unsigned i=0; i<chains.size(); ++i) { + unsigned r_start, r_end; std::string errmsg, mm, nn; + pdb.getResidueRange( chains[i], r_start, r_end, errmsg ); + if( !useter ) { + std::string resname = pdb.getResidueName( r_start ); + if( MolDataClass::isTerminalGroup( mytype, resname ) ) r_start++; + resname = pdb.getResidueName( r_end ); + if( MolDataClass::isTerminalGroup( mytype, resname ) ) r_end--; } + Tools::convert(r_start,mm); Tools::convert(r_end,nn); + if(i==0) restrings[0] = mm + "-" + nn; + else restrings.push_back( mm + "-" + nn ); + } } - Tools::interpretRanges(restrings); - - // Convert the list of involved residues into a list of segments of chains - int nk, nj; std::vector< std::vector<unsigned> > segments; - std::vector<unsigned> thissegment; - Tools::convert(restrings[0],nk); thissegment.push_back(nk); - for(unsigned i=1;i<restrings.size();++i){ - Tools::convert(restrings[i-1],nk); - Tools::convert(restrings[i],nj); - if( (nk+1)!=nj || pdb.getChainID(nk)!=pdb.getChainID(nj) ){ - segments.push_back(thissegment); - thissegment.resize(0); - } - thissegment.push_back(nj); + } + Tools::interpretRanges(restrings); + + // Convert the list of involved residues into a list of segments of chains + int nk, nj; std::vector< std::vector<unsigned> > segments; + std::vector<unsigned> thissegment; + Tools::convert(restrings[0],nk); thissegment.push_back(nk); + for(unsigned i=1; i<restrings.size(); ++i) { + Tools::convert(restrings[i-1],nk); + Tools::convert(restrings[i],nj); + if( (nk+1)!=nj || pdb.getChainID(nk)!=pdb.getChainID(nj) ) { + segments.push_back(thissegment); + thissegment.resize(0); } - segments.push_back( thissegment ); - - // And now get the backbone atoms from each segment - backbone.resize( segments.size() ); - std::vector<AtomNumber> atomnumbers; - for(unsigned i=0;i<segments.size();++i){ - for(unsigned j=0;j<segments[i].size();++j){ - std::string resname=pdb.getResidueName( segments[i][j] ); - if( !MolDataClass::allowedResidue(mytype, resname) ){ - std::string num; Tools::convert( segments[i][j], num ); - error("residue " + num + " is not recognized for moltype " + mytype ); - } - if( !useter && MolDataClass::isTerminalGroup( mytype, resname ) ){ - std::string num; Tools::convert( segments[i][j], num ); - error("residue " + num + " appears to be a terminal group"); - } - if( resname=="GLY" ) warning("GLY residues are achiral - assuming HA1 atom is in CB position"); - MolDataClass::getBackboneForResidue( mytype, segments[i][j], pdb, atomnumbers ); - if( atomnumbers.size()==0 ){ - std::string num; Tools::convert( segments[i][j], num ); - error("Could not find required backbone atom in residue number " + num ); - } else { - for(unsigned k=0;k<atomnumbers.size();++k) backbone[i].push_back( atomnumbers[k] ); - } - atomnumbers.resize(0); - } + thissegment.push_back(nj); + } + segments.push_back( thissegment ); + + // And now get the backbone atoms from each segment + backbone.resize( segments.size() ); + std::vector<AtomNumber> atomnumbers; + for(unsigned i=0; i<segments.size(); ++i) { + for(unsigned j=0; j<segments[i].size(); ++j) { + std::string resname=pdb.getResidueName( segments[i][j] ); + if( !MolDataClass::allowedResidue(mytype, resname) ) { + std::string num; Tools::convert( segments[i][j], num ); + error("residue " + num + " is not recognized for moltype " + mytype ); + } + if( !useter && MolDataClass::isTerminalGroup( mytype, resname ) ) { + std::string num; Tools::convert( segments[i][j], num ); + error("residue " + num + " appears to be a terminal group"); + } + if( resname=="GLY" ) warning("GLY residues are achiral - assuming HA1 atom is in CB position"); + MolDataClass::getBackboneForResidue( mytype, segments[i][j], pdb, atomnumbers ); + if( atomnumbers.size()==0 ) { + std::string num; Tools::convert( segments[i][j], num ); + error("Could not find required backbone atom in residue number " + num ); + } else { + for(unsigned k=0; k<atomnumbers.size(); ++k) backbone[i].push_back( atomnumbers[k] ); + } + atomnumbers.resize(0); } + } } } -void SetupMolInfo::interpretSymbol( const std::string& symbol, std::vector<AtomNumber>& atoms )const{ +void SetupMolInfo::interpretSymbol( const std::string& symbol, std::vector<AtomNumber>& atoms )const { MolDataClass::specialSymbol( mytype, symbol, pdb, atoms ); } -std::string SetupMolInfo::getAtomName(AtomNumber a)const{ +std::string SetupMolInfo::getAtomName(AtomNumber a)const { return pdb.getAtomName(a); } -unsigned SetupMolInfo::getResidueNumber(AtomNumber a)const{ +unsigned SetupMolInfo::getResidueNumber(AtomNumber a)const { return pdb.getResidueNumber(a); } -std::string SetupMolInfo::getResidueName(AtomNumber a)const{ +std::string SetupMolInfo::getResidueName(AtomNumber a)const { return pdb.getResidueName(a); } diff --git a/src/core/SetupMolInfo.h b/src/core/SetupMolInfo.h index f347f616f..362073b8b 100644 --- a/src/core/SetupMolInfo.h +++ b/src/core/SetupMolInfo.h @@ -30,9 +30,9 @@ namespace PLMD { class PDB; -class SetupMolInfo : -public ActionSetup, -public ActionAtomistic { +class SetupMolInfo : + public ActionSetup, + public ActionAtomistic { private: /// A pdb file containing the topology PDB& pdb; diff --git a/src/core/TargetDist.cpp b/src/core/TargetDist.cpp index 4a666a8e0..1bed18449 100644 --- a/src/core/TargetDist.cpp +++ b/src/core/TargetDist.cpp @@ -27,44 +27,44 @@ namespace PLMD { -void TargetDist::read( const PDB& pdb, std::vector<Value*> ar ){ +void TargetDist::read( const PDB& pdb, std::vector<Value*> ar ) { // Clear values in target actions - for(unsigned i=0;i<ar.size();++i){ - (ar[i]->getPntrToAction())->clearInputForces(); - (ar[i]->getPntrToAction())->clearDerivatives(); + for(unsigned i=0; i<ar.size(); ++i) { + (ar[i]->getPntrToAction())->clearInputForces(); + (ar[i]->getPntrToAction())->clearDerivatives(); } // Caclulate target actions from input in PDB file std::vector<double> targ( ar.size() ); - for(unsigned i=0;i<ar.size();++i){ - if( ar[i]->valueHasBeenSet() ){ - targ[i]=ar[i]->get(); - } else { - (ar[i]->getPntrToAction())->calculateFromPDB( pdb ); - targ[i]=ar[i]->get(); - } + for(unsigned i=0; i<ar.size(); ++i) { + if( ar[i]->valueHasBeenSet() ) { + targ[i]=ar[i]->get(); + } else { + (ar[i]->getPntrToAction())->calculateFromPDB( pdb ); + targ[i]=ar[i]->get(); + } } read( targ, ar ); } -void TargetDist::read( const std::vector<double>& targ, std::vector<Value*> ar ){ +void TargetDist::read( const std::vector<double>& targ, std::vector<Value*> ar ) { plumed_assert( targ.size()==ar.size() ); target.resize( ar.size() ); args.resize( ar.size() ); log.printf(" distance from this point in cv space : "); - for(unsigned i=0;i<target.size();++i){ log.printf("%f ", targ[i]); target[i]=targ[i]; args[i]=ar[i]; } + for(unsigned i=0; i<target.size(); ++i) { log.printf("%f ", targ[i]); target[i]=targ[i]; args[i]=ar[i]; } log.printf("\n"); } -double TargetDist::calculate( std::vector<double>& derivs ){ +double TargetDist::calculate( std::vector<double>& derivs ) { plumed_assert( derivs.size()==args.size() ); double dist=0; - for(unsigned i=0;i<args.size();++i){ - double tmp=args[i]->difference( target[i], args[i]->get() ); - derivs[i]=tmp; dist+=tmp*tmp; + for(unsigned i=0; i<args.size(); ++i) { + double tmp=args[i]->difference( target[i], args[i]->get() ); + derivs[i]=tmp; dist+=tmp*tmp; } dist=sqrt(dist); - for(unsigned i=0;i<args.size();++i) derivs[i]/=dist; + for(unsigned i=0; i<args.size(); ++i) derivs[i]/=dist; return dist; } diff --git a/src/core/TargetDist.h b/src/core/TargetDist.h index b4bd3b137..f90b8a4be 100644 --- a/src/core/TargetDist.h +++ b/src/core/TargetDist.h @@ -25,7 +25,7 @@ #include <vector> #include <string> -namespace PLMD{ +namespace PLMD { class Log; class PDB; @@ -33,12 +33,12 @@ class Value; class TargetDist { private: - std::vector<Value*> args; + std::vector<Value*> args; std::vector<double> target; Log &log; public: explicit TargetDist(Log& log) : log(log) {} - void read( const PDB& pdb, std::vector<Value*> args ); + void read( const PDB& pdb, std::vector<Value*> args ); void read( const std::vector<double>& targ, std::vector<Value*> ar ); double calculate( std::vector<double>& derivs ); }; diff --git a/src/core/Value.cpp b/src/core/Value.cpp index b1fd605b5..76d43a0ac 100644 --- a/src/core/Value.cpp +++ b/src/core/Value.cpp @@ -28,19 +28,19 @@ #include "Atoms.h" #include "PlumedMain.h" -namespace PLMD{ +namespace PLMD { Value::Value(): - action(NULL), - value_set(false), - value(0.0), + action(NULL), + value_set(false), + value(0.0), inputForce(0.0), hasForce(false), - hasDeriv(true), - periodicity(unset), - min(0.0), - max(0.0), - max_minus_min(0.0), + hasDeriv(true), + periodicity(unset), + min(0.0), + max(0.0), + max_minus_min(0.0), inv_max_minus_min(0.0) { } @@ -61,18 +61,18 @@ Value::Value(ActionWithValue* av, const std::string& name, const bool withderiv) { } -void Value::setupPeriodicity(){ - if( min==0 && max==0 ){ - periodicity=notperiodic; +void Value::setupPeriodicity() { + if( min==0 && max==0 ) { + periodicity=notperiodic; } else { - periodicity=periodic; - max_minus_min=max-min; - plumed_massert(max_minus_min>0, "your function has a very strange domain?"); - inv_max_minus_min=1.0/max_minus_min; + periodicity=periodic; + max_minus_min=max-min; + plumed_massert(max_minus_min>0, "your function has a very strange domain?"); + inv_max_minus_min=1.0/max_minus_min; } } -bool Value::isPeriodic()const{ +bool Value::isPeriodic()const { plumed_massert(periodicity!=unset,"periodicity should be set"); return periodicity==periodic; } @@ -81,18 +81,18 @@ bool Value::applyForce(std::vector<double>& forces ) const { if( !hasForce ) return false; plumed_dbg_massert( derivatives.size()==forces.size()," forces array has wrong size" ); const unsigned N=derivatives.size(); - for(unsigned i=0;i<N;++i) forces[i]=inputForce*derivatives[i]; + for(unsigned i=0; i<N; ++i) forces[i]=inputForce*derivatives[i]; return true; } -void Value::setNotPeriodic(){ +void Value::setNotPeriodic() { min=0; max=0; periodicity=notperiodic; } -void Value::setDomain(const std::string& pmin,const std::string& pmax){ - str_min=pmin; - if( !Tools::convert(str_min,min) ) action->error("could not convert period string " + str_min + " to real"); - str_max=pmax; +void Value::setDomain(const std::string& pmin,const std::string& pmax) { + str_min=pmin; + if( !Tools::convert(str_min,min) ) action->error("could not convert period string " + str_min + " to real"); + str_max=pmax; if( !Tools::convert(str_max,max) ) action->error("could not convert period string " + str_max + " to read"); setupPeriodicity(); } @@ -109,28 +109,28 @@ void Value::getDomain(double&minout,double&maxout) const { maxout=max; } -void Value::setGradients(){ +void Value::setGradients() { gradients.clear(); ActionAtomistic*aa=dynamic_cast<ActionAtomistic*>(action); ActionWithArguments*aw=dynamic_cast<ActionWithArguments*>(action); - if(aa){ + if(aa) { Atoms&atoms((aa->plumed).getAtoms()); - for(unsigned j=0;j<aa->getNumberOfAtoms();++j){ + for(unsigned j=0; j<aa->getNumberOfAtoms(); ++j) { AtomNumber an=aa->getAbsoluteIndex(j); - if(atoms.isVirtualAtom(an)){ + if(atoms.isVirtualAtom(an)) { const ActionWithVirtualAtom* a=atoms.getVirtualAtomsAction(an); - for(const auto & p : a->getGradients()){ + for(const auto & p : a->getGradients()) { // controllare l'ordine del matmul: gradients[p.first]+=matmul(Vector(derivatives[3*j],derivatives[3*j+1],derivatives[3*j+2]),p.second); } } else { - for(unsigned i=0;i<3;i++) gradients[an][i]+=derivatives[3*j+i]; + for(unsigned i=0; i<3; i++) gradients[an][i]+=derivatives[3*j+i]; } } - } else if(aw){ + } else if(aw) { std::vector<Value*> values=aw->getArguments(); - for(unsigned j=0;j<derivatives.size();j++){ - for(const auto & p : values[j]->gradients){ + for(unsigned j=0; j<derivatives.size(); j++) { + for(const auto & p : values[j]->gradients) { AtomNumber iatom=p.first; gradients[iatom]+=p.second*derivatives[j]; } @@ -138,44 +138,44 @@ void Value::setGradients(){ } else plumed_error(); } -double Value::projection(const Value& v1,const Value&v2){ +double Value::projection(const Value& v1,const Value&v2) { double proj=0.0; const std::map<AtomNumber,Vector> & grad1(v1.gradients); const std::map<AtomNumber,Vector> & grad2(v2.gradients); - for(const auto & p1 : grad1){ + for(const auto & p1 : grad1) { AtomNumber a=p1.first; const auto p2=grad2.find(a); - if(p2!=grad2.end()){ + if(p2!=grad2.end()) { proj+=dotProduct(p1.second,(*p2).second); } } return proj; } -ActionWithValue* Value::getPntrToAction(){ +ActionWithValue* Value::getPntrToAction() { plumed_assert( action!=NULL ); return action; } -void copy( const Value& val1, Value& val2 ){ +void copy( const Value& val1, Value& val2 ) { unsigned nder=val1.getNumberOfDerivatives(); - if( nder!=val2.getNumberOfDerivatives() ){ val2.resizeDerivatives( nder ); } + if( nder!=val2.getNumberOfDerivatives() ) { val2.resizeDerivatives( nder ); } val2.clearDerivatives(); - for(unsigned i=0;i<val1.getNumberOfDerivatives();++i) val2.addDerivative( i, val1.getDerivative(i) ); + for(unsigned i=0; i<val1.getNumberOfDerivatives(); ++i) val2.addDerivative( i, val1.getDerivative(i) ); val2.set( val1.get() ); } -void copy( const Value& val1, Value* val2 ){ +void copy( const Value& val1, Value* val2 ) { unsigned nder=val1.getNumberOfDerivatives(); - if( nder!=val2->getNumberOfDerivatives() ){ val2->resizeDerivatives( nder ); } + if( nder!=val2->getNumberOfDerivatives() ) { val2->resizeDerivatives( nder ); } val2->clearDerivatives(); - for(unsigned i=0;i<val1.getNumberOfDerivatives();++i) val2->addDerivative( i, val1.getDerivative(i) ); + for(unsigned i=0; i<val1.getNumberOfDerivatives(); ++i) val2->addDerivative( i, val1.getDerivative(i) ); val2->set( val1.get() ); } -void add( const Value& val1, Value* val2 ){ +void add( const Value& val1, Value* val2 ) { plumed_assert( val1.getNumberOfDerivatives()==val2->getNumberOfDerivatives() ); - for(unsigned i=0;i<val1.getNumberOfDerivatives();++i) val2->addDerivative( i, val1.getDerivative(i) ); + for(unsigned i=0; i<val1.getNumberOfDerivatives(); ++i) val2->addDerivative( i, val1.getDerivative(i) ); val2->set( val1.get() + val2->get() ); } diff --git a/src/core/Value.h b/src/core/Value.h index d1a8509c7..6bbd9b6ce 100644 --- a/src/core/Value.h +++ b/src/core/Value.h @@ -30,31 +30,31 @@ #include "tools/AtomNumber.h" #include "tools/Vector.h" -namespace PLMD{ +namespace PLMD { class ActionWithValue; /// \ingroup TOOLBOX /// A class for holding the value of a function together with its derivatives. -/// Typically, an object of type PLMD::ActionWithValue will contain one -/// object of type PLUMD::Value that will be named after the label. If the -/// PLMD::ActionWithValue is part of a class that calculates multiple components +/// Typically, an object of type PLMD::ActionWithValue will contain one +/// object of type PLUMD::Value that will be named after the label. If the +/// PLMD::ActionWithValue is part of a class that calculates multiple components /// then the class will contain multiple that will be called label.component-name -/// This class is used to pass information between different PLMD::Action +/// This class is used to pass information between different PLMD::Action /// objects. However, if you find a use for a tempory PLMD::Value in some method /// you are implementing please feel free to use it. -class Value{ -friend class ActionWithValue; +class Value { + friend class ActionWithValue; /// This copies the contents of a value into a second value (just the derivatives and value) -friend void copy( const Value& val1, Value& val2 ); + friend void copy( const Value& val1, Value& val2 ); /// This copies the contents of a value into a second value (but second value is a pointer) -friend void copy( const Value& val, Value* val2 ); + friend void copy( const Value& val, Value* val2 ); /// This adds some derivatives onto the value -friend void add( const Value& val1, Value* valout ); + friend void add( const Value& val1, Value* valout ); /// This calculates val1*val2 and sorts out the derivatives -friend void product( const Value& val1, const Value& val2, Value& valout ); + friend void product( const Value& val1, const Value& val2, Value& valout ); /// This calculates va1/val2 and sorts out the derivatives -friend void quotient( const Value& val1, const Value& val2, Value* valout ); + friend void quotient( const Value& val1, const Value& val2, Value* valout ); private: /// The action in which this quantity is calculated ActionWithValue* action; @@ -89,7 +89,7 @@ public: Value(); /// A constructor that is used throughout the code to setup the value poiters Value(ActionWithValue* av, const std::string& name, const bool withderiv); -/// Set the value of the function +/// Set the value of the function void set(double); /// Add something to the value of the function void add(double); @@ -102,7 +102,7 @@ public: /// Set the function not periodic void setNotPeriodic(); /// Set the domain of the function - void setDomain(const std::string&, const std::string&); + void setDomain(const std::string&, const std::string&); /// Get the domain of the quantity void getDomain(std::string&,std::string&) const; /// Get the domain of the quantity @@ -112,7 +112,7 @@ public: /// Check whether or not this particular quantity has derivatives bool hasDerivatives()const; /// Get the number of derivatives that this particular value has - unsigned getNumberOfDerivatives() const; + unsigned getNumberOfDerivatives() const; /// Set the number of derivatives void resizeDerivatives(int n); /// Set all the derivatives to zero @@ -135,7 +135,7 @@ public: bool applyForce( std::vector<double>& forces ) const ; /// Calculate the difference between the instantaneous value of the function and some other point: other_point-inst_val double difference(double)const; -/// Calculate the difference between two values of this function: d2 -d1 +/// Calculate the difference between two values of this function: d2 -d1 double difference(double d1,double d2)const; /// This returns the pointer to the action where this value is calculated ActionWithValue* getPntrToAction(); @@ -151,57 +151,57 @@ void copy( const Value& val1, Value* val2 ); void add( const Value& val1, Value* valout ); inline -void Value::applyPeriodicity(){ - if(periodicity==periodic){ +void Value::applyPeriodicity() { + if(periodicity==periodic) { value=min+difference(min,value); if(value<min)value+=max_minus_min; } } inline -void product( const Value& val1, const Value& val2, Value& valout ){ +void product( const Value& val1, const Value& val2, Value& valout ) { plumed_assert( val1.derivatives.size()==val2.derivatives.size() ); if( valout.derivatives.size()!=val1.derivatives.size() ) valout.resizeDerivatives( val1.derivatives.size() ); - valout.value_set=false; + valout.value_set=false; valout.clearDerivatives(); - double u=val1.value; + double u=val1.value; double v=val2.value; - for(unsigned i=0;i<val1.derivatives.size();++i){ - valout.addDerivative(i, u*val2.derivatives[i] + v*val1.derivatives[i] ); + for(unsigned i=0; i<val1.derivatives.size(); ++i) { + valout.addDerivative(i, u*val2.derivatives[i] + v*val1.derivatives[i] ); } valout.set( u*v ); } inline -void quotient( const Value& val1, const Value& val2, Value* valout ){ +void quotient( const Value& val1, const Value& val2, Value* valout ) { plumed_assert( val1.derivatives.size()==val2.derivatives.size() ); if( valout->derivatives.size()!=val1.derivatives.size() ) valout->resizeDerivatives( val1.derivatives.size() ); - valout->value_set=false; + valout->value_set=false; valout->clearDerivatives(); - double u=val1.get(); + double u=val1.get(); double v=val2.get(); - for(unsigned i=0;i<val1.getNumberOfDerivatives();++i){ - valout->addDerivative(i, v*val1.getDerivative(i) - u*val2.getDerivative(i) ); + for(unsigned i=0; i<val1.getNumberOfDerivatives(); ++i) { + valout->addDerivative(i, v*val1.getDerivative(i) - u*val2.getDerivative(i) ); } valout->chainRule( 1/(v*v) ); valout->set( u / v ); } inline -void Value::set(double v){ +void Value::set(double v) { value_set=true; value=v; applyPeriodicity(); } inline -void Value::add(double v){ +void Value::add(double v) { value_set=true; value+=v; applyPeriodicity(); } inline -double Value::get()const{ +double Value::get()const { return value; } @@ -211,7 +211,7 @@ bool Value::valueHasBeenSet() const { } inline -const std::string& Value::getName()const{ +const std::string& Value::getName()const { return name; } @@ -233,41 +233,41 @@ bool Value::hasDerivatives() const { } inline -void Value::resizeDerivatives(int n){ +void Value::resizeDerivatives(int n) { if(hasDeriv) derivatives.resize(n); } inline -void Value::addDerivative(unsigned i,double d){ +void Value::addDerivative(unsigned i,double d) { plumed_dbg_massert(i<derivatives.size(),"derivative is out of bounds"); derivatives[i]+=d; } inline -void Value::setDerivative(unsigned i, double d){ +void Value::setDerivative(unsigned i, double d) { plumed_dbg_massert(i<derivatives.size(),"derivative is out of bounds"); derivatives[i]=d; } inline -void Value::chainRule(double df){ - for(unsigned i=0;i<derivatives.size();++i) derivatives[i]*=df; +void Value::chainRule(double df) { + for(unsigned i=0; i<derivatives.size(); ++i) derivatives[i]*=df; } inline -void Value::clearInputForce(){ +void Value::clearInputForce() { hasForce=false; inputForce=0.0; } inline -void Value::clearDerivatives(){ +void Value::clearDerivatives() { value_set=false; std::fill(derivatives.begin(), derivatives.end(), 0); } inline -void Value::addForce(double f){ +void Value::addForce(double f) { plumed_dbg_massert(hasDerivatives(),"forces can only be added to values with derivatives"); hasForce=true; inputForce+=f; @@ -279,10 +279,10 @@ double Value::getForce() const { } /// d2-d1 inline -double Value::difference(double d1,double d2)const{ - if(periodicity==notperiodic){ +double Value::difference(double d1,double d2)const { + if(periodicity==notperiodic) { return d2-d1; - }else if(periodicity==periodic){ + } else if(periodicity==periodic) { double s=(d2-d1)*inv_max_minus_min; // remember: pbc brings the difference in a range of -0.5:0.5 s=Tools::pbc(s); @@ -291,12 +291,12 @@ double Value::difference(double d1,double d2)const{ } inline -double Value::bringBackInPbc(double d1)const{ - return difference(min+max_minus_min/2. , d1); +double Value::bringBackInPbc(double d1)const { + return difference(min+max_minus_min/2., d1); } inline -double Value::difference(double d)const{ +double Value::difference(double d)const { return difference(get(),d); } diff --git a/src/core/WithCmd.h b/src/core/WithCmd.h index e94e997b5..0397c2e5c 100644 --- a/src/core/WithCmd.h +++ b/src/core/WithCmd.h @@ -24,14 +24,14 @@ #include <string> -namespace PLMD{ +namespace PLMD { /// Base for classes with cmd() method. /// This is an abstract base class for classes with /// cmd() method. It takes care of "const" cast, and /// in the future it may be used to enforce some sort /// of type checking on passed arguments. -class WithCmd{ +class WithCmd { public: virtual ~WithCmd(); /// Const val version, which indeed just overrides the const and call the virtual method. @@ -41,7 +41,7 @@ public: }; inline -void WithCmd::cmd(const std::string& key,const void*val){ +void WithCmd::cmd(const std::string& key,const void*val) { // this is nasty trick: cmd(key,const_cast<void*>(val)); // in this manner, a const pointer can be used for val, allowing the user to pass @@ -50,7 +50,7 @@ void WithCmd::cmd(const std::string& key,const void*val){ } inline -WithCmd::~WithCmd(){ +WithCmd::~WithCmd() { // do nothing // here just to allow inheriting from this class properly } diff --git a/src/crystallization/BondOrientation.cpp b/src/crystallization/BondOrientation.cpp index 450cc3b94..638d70bf5 100644 --- a/src/crystallization/BondOrientation.cpp +++ b/src/crystallization/BondOrientation.cpp @@ -49,49 +49,49 @@ public: PLUMED_REGISTER_ACTION(BondOrientation,"BOND_DIRECTIONS") -void BondOrientation::registerKeywords( Keywords& keys ){ +void BondOrientation::registerKeywords( Keywords& keys ) { VectorMultiColvar::registerKeywords( keys ); keys.add("numbered","ATOMS","the atoms involved in each of the vectors you wish to calculate. " - "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one vector will be " - "calculated for each ATOM keyword you specify (all ATOM keywords should " - "specify the indices of two atoms). The eventual number of quantities calculated by this " - "action will depend on what functions of the distribution you choose to calculate."); + "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one vector will be " + "calculated for each ATOM keyword you specify (all ATOM keywords should " + "specify the indices of two atoms). The eventual number of quantities calculated by this " + "action will depend on what functions of the distribution you choose to calculate."); keys.reset_style("ATOMS","atoms"); keys.add("atoms-1","GROUP","Calculate the distance between each distinct pair of atoms in the group"); keys.add("atoms-2","GROUPA","Calculate the distances between all the atoms in GROUPA and all " - "the atoms in GROUPB. This must be used in conjuction with GROUPB."); + "the atoms in GROUPB. This must be used in conjuction with GROUPB."); keys.add("atoms-2","GROUPB","Calculate the distances between all the atoms in GROUPA and all the atoms " - "in GROUPB. This must be used in conjuction with GROUPA."); + "in GROUPB. This must be used in conjuction with GROUPA."); keys.add("compulsory","NN","12","The n parameter of the switching function "); keys.add("compulsory","MM","0","The m parameter of the switching function; 0 implies 2*NN"); keys.add("compulsory","D_0","0.0","The d_0 parameter of the switching function"); keys.add("compulsory","R_0","The r_0 parameter of the switching function"); keys.add("optional","SWITCH","This keyword is used if you want to employ an alternative to the continuous swiching function defined above. " - "The following provides information on the \\ref switchingfunction that are available. " - "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); + "The following provides information on the \\ref switchingfunction that are available. " + "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); keys.use("VMEAN"); keys.use("VSUM"); } BondOrientation::BondOrientation( const ActionOptions& ao ): -Action(ao), -VectorMultiColvar(ao) + Action(ao), + VectorMultiColvar(ao) { // Read atoms weightHasDerivatives=true; - std::vector<AtomNumber> all_atoms; + std::vector<AtomNumber> all_atoms; readTwoGroups( "GROUP", "GROUPA", "GROUPB", all_atoms ); - if( atom_lab.size()==0 ) readAtomsLikeKeyword( "ATOMS", 2, all_atoms ); + if( atom_lab.size()==0 ) readAtomsLikeKeyword( "ATOMS", 2, all_atoms ); setupMultiColvarBase( all_atoms ); // Read in the switching function std::string sw, errors; parse("SWITCH",sw); - if(sw.length()>0){ - switchingFunction.set(sw,errors); + if(sw.length()>0) { + switchingFunction.set(sw,errors); } else { - double r_0=-1.0, d_0; int nn, mm; - parse("NN",nn); parse("MM",mm); - parse("R_0",r_0); parse("D_0",d_0); - if( r_0<0.0 ) error("you must set a value for R_0"); - switchingFunction.set(nn,mm,r_0,d_0); + double r_0=-1.0, d_0; int nn, mm; + parse("NN",nn); parse("MM",mm); + parse("R_0",r_0); parse("D_0",d_0); + if( r_0<0.0 ) error("you must set a value for R_0"); + switchingFunction.set(nn,mm,r_0,d_0); } log.printf(" orientation of those bonds with lengths are less than %s\n",( switchingFunction.description() ).c_str() ); // Set the link cell cutoff @@ -106,10 +106,10 @@ double BondOrientation::calculateWeight( const unsigned& current, const double& if( distm>rcut2 ) return 0.0; double df, ww=switchingFunction.calculateSqr( distm, df ); // Derivatives of weights - addAtomDerivatives( 0, 0, -df*weight*distance, myatoms ); + addAtomDerivatives( 0, 0, -df*weight*distance, myatoms ); addAtomDerivatives( 0, 1, df*weight*distance, myatoms ); myatoms.addBoxDerivatives( 0, (-df)*weight*Tensor(distance,distance) ); - return ww; + return ww; } void BondOrientation::calculateVector( multicolvar::AtomValuePack& myatoms ) const { @@ -125,11 +125,11 @@ void BondOrientation::calculateVector( multicolvar::AtomValuePack& myatoms ) con myatoms.addBoxDerivatives( 3, Tensor(distance,Vector(0,-1.0,0)) ); myatoms.addValue( 3, distance[1] ); - addAtomDerivatives( 4 , 0, Vector(0,0,-1.0), myatoms ); - addAtomDerivatives( 4 , 1, Vector(0,0,+1.0), myatoms ); + addAtomDerivatives( 4, 0, Vector(0,0,-1.0), myatoms ); + addAtomDerivatives( 4, 1, Vector(0,0,+1.0), myatoms ); myatoms.addBoxDerivatives( 4, Tensor(distance,Vector(0,0,-1.0)) ); myatoms.addValue( 4, distance[2] ); } } -} +} diff --git a/src/crystallization/CubicHarmonicBase.cpp b/src/crystallization/CubicHarmonicBase.cpp index 3d793a0dc..04a07426e 100644 --- a/src/crystallization/CubicHarmonicBase.cpp +++ b/src/crystallization/CubicHarmonicBase.cpp @@ -27,10 +27,10 @@ using namespace std; -namespace PLMD{ -namespace crystallization{ +namespace PLMD { +namespace crystallization { -void CubicHarmonicBase::registerKeywords( Keywords& keys ){ +void CubicHarmonicBase::registerKeywords( Keywords& keys ) { multicolvar::MultiColvarBase::registerKeywords( keys ); keys.use("SPECIES"); keys.use("SPECIESA"); keys.use("SPECIESB"); keys.add("compulsory","NN","6","The n parameter of the switching function "); @@ -38,8 +38,8 @@ void CubicHarmonicBase::registerKeywords( Keywords& keys ){ keys.add("compulsory","D_0","0.0","The d_0 parameter of the switching function"); keys.add("compulsory","R_0","The r_0 parameter of the switching function"); keys.add("optional","SWITCH","This keyword is used if you want to employ an alternative to the continuous swiching function defined above. " - "The following provides information on the \\ref switchingfunction that are available. " - "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); + "The following provides information on the \\ref switchingfunction that are available. " + "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); keys.add("compulsory","PHI","0.0","The Euler rotational angle phi"); keys.add("compulsory","THETA","0.0","The Euler rotational angle theta"); keys.add("compulsory","PSI","0.0","The Euler rotational angle psi"); @@ -47,42 +47,42 @@ void CubicHarmonicBase::registerKeywords( Keywords& keys ){ // Use actionWithDistributionKeywords keys.use("MEAN"); keys.use("MORE_THAN"); keys.use("LESS_THAN"); keys.use("MAX"); keys.use("MIN"); keys.use("BETWEEN"); keys.use("HISTOGRAM"); keys.use("MOMENTS"); - keys.use("ALT_MIN"); keys.use("LOWEST"); keys.use("HIGHEST"); + keys.use("ALT_MIN"); keys.use("LOWEST"); keys.use("HIGHEST"); } CubicHarmonicBase::CubicHarmonicBase(const ActionOptions&ao): -Action(ao), -MultiColvarBase(ao) + Action(ao), + MultiColvarBase(ao) { // Read in the switching function std::string sw, errors; parse("SWITCH",sw); - if(sw.length()>0){ - switchingFunction.set(sw,errors); - if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); - } else { - double r_0=-1.0, d_0; int nn, mm; - parse("NN",nn); parse("MM",mm); - parse("R_0",r_0); parse("D_0",d_0); - if( r_0<0.0 ) error("you must set a value for R_0"); - switchingFunction.set(nn,mm,r_0,d_0); + if(sw.length()>0) { + switchingFunction.set(sw,errors); + if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); + } else { + double r_0=-1.0, d_0; int nn, mm; + parse("NN",nn); parse("MM",mm); + parse("R_0",r_0); parse("D_0",d_0); + if( r_0<0.0 ) error("you must set a value for R_0"); + switchingFunction.set(nn,mm,r_0,d_0); } - + double phi, theta, psi; parse("PHI",phi); parse("THETA",theta); parse("PSI",psi); log.printf(" creating rotation matrix with Euler angles phi=%f, theta=%f and psi=%f\n",phi,theta,psi); // Calculate the rotation matrix http://mathworld.wolfram.com/EulerAngles.html rotationmatrix[0][0]=cos(psi)*cos(phi)-cos(theta)*sin(phi)*sin(psi); rotationmatrix[0][1]=cos(psi)*sin(phi)+cos(theta)*cos(phi)*sin(psi); rotationmatrix[0][2]=sin(psi)*sin(theta); - + rotationmatrix[1][0]=-sin(psi)*cos(phi)-cos(theta)*sin(phi)*cos(psi); rotationmatrix[1][1]=-sin(psi)*sin(phi)+cos(theta)*cos(phi)*cos(psi); rotationmatrix[1][2]=cos(psi)*sin(theta); - + rotationmatrix[2][0]=sin(theta)*sin(phi); rotationmatrix[2][1]=-sin(theta)*cos(phi); rotationmatrix[2][2]=cos(theta); - - + + log.printf(" measure crystallinity around central atom. Includes those atoms within %s\n",( switchingFunction.description() ).c_str() ); parseFlag("UNORMALIZED",unormalized); if( unormalized ) log.printf(" output sum of vector functions \n"); @@ -91,57 +91,57 @@ MultiColvarBase(ao) rcut2 = switchingFunction.get_dmax()*switchingFunction.get_dmax(); setLinkCellCutoff( switchingFunction.get_dmax() ); // And setup the ActionWithVessel - std::vector<AtomNumber> all_atoms; setupMultiColvarBase( all_atoms ); + std::vector<AtomNumber> all_atoms; setupMultiColvarBase( all_atoms ); } double CubicHarmonicBase::compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ) const { - double dfunc; Vector rotatedis; - - // Calculate the coordination number - Vector myder, rotateder, fder; unsigned nat=myatoms.getNumberOfAtoms(); - - double d2; - for(unsigned i=1;i<nat;++i){ - Vector& distance=myatoms.getPosition(i); - - if ( (d2=distance[0]*distance[0])<rcut2 && - (d2+=distance[1]*distance[1])<rcut2 && - (d2+=distance[2]*distance[2])<rcut2) { - - double sw = switchingFunction.calculateSqr( d2, dfunc ); - - rotatedis[0]=rotationmatrix[0][0]*distance[0] - +rotationmatrix[0][1]*distance[1] - +rotationmatrix[0][2]*distance[2]; - rotatedis[1]=rotationmatrix[1][0]*distance[0] - +rotationmatrix[1][1]*distance[1] - +rotationmatrix[1][2]*distance[2]; - rotatedis[2]=rotationmatrix[2][0]*distance[0] - +rotationmatrix[2][1]*distance[1] - +rotationmatrix[2][2]*distance[2]; - - double tmp = calculateCubicHarmonic( rotatedis, d2, rotateder ); - - myder[0]=rotationmatrix[0][0]*rotateder[0] - +rotationmatrix[1][0]*rotateder[1] - +rotationmatrix[2][0]*rotateder[2]; - myder[1]=rotationmatrix[0][1]*rotateder[0] - +rotationmatrix[1][1]*rotateder[1] - +rotationmatrix[2][1]*rotateder[2]; - myder[2]=rotationmatrix[0][2]*rotateder[0] - +rotationmatrix[1][2]*rotateder[1] - +rotationmatrix[2][2]*rotateder[2]; - - fder = (+dfunc)*tmp*distance + sw*myder; - - accumulateSymmetryFunction( 1, i, sw*tmp, fder, Tensor(distance,-fder), myatoms ); - accumulateSymmetryFunction( -1, i, sw, (+dfunc)*distance, (-dfunc)*Tensor(distance,distance), myatoms ); - } - } - // values -> der of... value [0], weight[1], x coord [2], y, z... [more magic] - updateActiveAtoms( myatoms ); - if( !unormalized ) myatoms.getUnderlyingMultiValue().quotientRule( 1, 1 ); - return myatoms.getValue(1); // this is equivalent to getting an "atomic" CV + double dfunc; Vector rotatedis; + + // Calculate the coordination number + Vector myder, rotateder, fder; unsigned nat=myatoms.getNumberOfAtoms(); + + double d2; + for(unsigned i=1; i<nat; ++i) { + Vector& distance=myatoms.getPosition(i); + + if ( (d2=distance[0]*distance[0])<rcut2 && + (d2+=distance[1]*distance[1])<rcut2 && + (d2+=distance[2]*distance[2])<rcut2) { + + double sw = switchingFunction.calculateSqr( d2, dfunc ); + + rotatedis[0]=rotationmatrix[0][0]*distance[0] + +rotationmatrix[0][1]*distance[1] + +rotationmatrix[0][2]*distance[2]; + rotatedis[1]=rotationmatrix[1][0]*distance[0] + +rotationmatrix[1][1]*distance[1] + +rotationmatrix[1][2]*distance[2]; + rotatedis[2]=rotationmatrix[2][0]*distance[0] + +rotationmatrix[2][1]*distance[1] + +rotationmatrix[2][2]*distance[2]; + + double tmp = calculateCubicHarmonic( rotatedis, d2, rotateder ); + + myder[0]=rotationmatrix[0][0]*rotateder[0] + +rotationmatrix[1][0]*rotateder[1] + +rotationmatrix[2][0]*rotateder[2]; + myder[1]=rotationmatrix[0][1]*rotateder[0] + +rotationmatrix[1][1]*rotateder[1] + +rotationmatrix[2][1]*rotateder[2]; + myder[2]=rotationmatrix[0][2]*rotateder[0] + +rotationmatrix[1][2]*rotateder[1] + +rotationmatrix[2][2]*rotateder[2]; + + fder = (+dfunc)*tmp*distance + sw*myder; + + accumulateSymmetryFunction( 1, i, sw*tmp, fder, Tensor(distance,-fder), myatoms ); + accumulateSymmetryFunction( -1, i, sw, (+dfunc)*distance, (-dfunc)*Tensor(distance,distance), myatoms ); + } + } + // values -> der of... value [0], weight[1], x coord [2], y, z... [more magic] + updateActiveAtoms( myatoms ); + if( !unormalized ) myatoms.getUnderlyingMultiValue().quotientRule( 1, 1 ); + return myatoms.getValue(1); // this is equivalent to getting an "atomic" CV } } diff --git a/src/crystallization/CubicHarmonicBase.h b/src/crystallization/CubicHarmonicBase.h index 8cc2408e8..7986038a4 100644 --- a/src/crystallization/CubicHarmonicBase.h +++ b/src/crystallization/CubicHarmonicBase.h @@ -26,8 +26,8 @@ #include "multicolvar/AtomValuePack.h" #include "tools/SwitchingFunction.h" -namespace PLMD{ -namespace crystallization{ +namespace PLMD { +namespace crystallization { class CubicHarmonicBase : public multicolvar::MultiColvarBase { private: @@ -43,7 +43,7 @@ public: double compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ) const ; virtual double calculateCubicHarmonic( const Vector& distance, const double& d2, Vector& myder ) const = 0; /// Returns the number of coordinates of the field - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } }; } diff --git a/src/crystallization/Fccubic.cpp b/src/crystallization/Fccubic.cpp index cf27beaf1..fc1793ab3 100644 --- a/src/crystallization/Fccubic.cpp +++ b/src/crystallization/Fccubic.cpp @@ -28,23 +28,23 @@ using namespace std; -namespace PLMD{ -namespace crystallization{ +namespace PLMD { +namespace crystallization { -//+PLUMEDOC MCOLVAR FCCUBIC +//+PLUMEDOC MCOLVAR FCCUBIC /* Measure how similar the environment around atoms is to that found in a FCC structure. This CV was introduced in this article \cite fcc-michele-1 and again in this article \cite fcc-michele-2 -This CV essentially determines whether the environment around any given atom is similar to that found in +This CV essentially determines whether the environment around any given atom is similar to that found in the FCC structure or not. The function that is used to make this determination is as follows: \f[ -s_i = \frac{ \sum_{i \ne j} \sigma(r_{ij}) \left\{ a\left[ \frac{(x_{ij}y_{ij})^4 + (x_{ij}z_{ij})^4 + (y_{ij}z_{ij})^4}{r_{ij}^8} - \frac{\alpha (x_{ij}y_{ij}z_{ij})^4}{r_{ij}^{12}} \right] + b \right\} }{ \sum_{i \ne j} \sigma(r_{ij}) } +s_i = \frac{ \sum_{i \ne j} \sigma(r_{ij}) \left\{ a\left[ \frac{(x_{ij}y_{ij})^4 + (x_{ij}z_{ij})^4 + (y_{ij}z_{ij})^4}{r_{ij}^8} - \frac{\alpha (x_{ij}y_{ij}z_{ij})^4}{r_{ij}^{12}} \right] + b \right\} }{ \sum_{i \ne j} \sigma(r_{ij}) } \f] -In this expression \f$x_{ij}\f$, \f$y_{ij}\f$ and \f$z_{ij}\f$ are the \f$x\f$, \f$y\f$ and \f$z\f$ components of the vector connecting atom \f$i\f$ to -atom \f$j\f$ and \f$r_{ij}\f$ is the magnitude of this vector. \f$\sigma(r_{ij})\f$ is a \ref switchingfunction that acts on the distance between +In this expression \f$x_{ij}\f$, \f$y_{ij}\f$ and \f$z_{ij}\f$ are the \f$x\f$, \f$y\f$ and \f$z\f$ components of the vector connecting atom \f$i\f$ to +atom \f$j\f$ and \f$r_{ij}\f$ is the magnitude of this vector. \f$\sigma(r_{ij})\f$ is a \ref switchingfunction that acts on the distance between atom \f$i\f$ and atom \f$j\f$ and its inclusion in the numerator and the denominator of the above expression as well as the fact that we are summing over all of the other atoms in the system ensures that we are calculating an average of the function of \f$x_{ij}\f$, \f$y_{ij}\f$ and \f$z_{ij}\f$ for the atoms in the first coordination sphere around atom \f$i\f$. Lastly, \f$\alpha\f$ @@ -52,15 +52,15 @@ is a parameter that can be set by the user, which by default is equal to three. \f[ a = \frac{ 80080}{ 2717 + 16 \alpha} \qquad \textrm{and} \qquad b = \frac{ 16(\alpha - 143) }{2717 + 16\alpha} -\f] +\f] This quantity is once again a multicolvar so you can compute it for multiple atoms using a single PLUMED action and then compute -the average value for the atoms in your system, the number of atoms that have an \f$s_i\f$ value that is more that some target and +the average value for the atoms in your system, the number of atoms that have an \f$s_i\f$ value that is more that some target and so on. Notice also that you can rotate the reference frame if you are using a non-standard unit cell. \par Examples -The following input calculates the FCCUBIC parameter for the 64 atoms in the system +The following input calculates the FCCUBIC parameter for the 64 atoms in the system and then calculates and prints the average value for this quantity. \verbatim @@ -83,14 +83,14 @@ public: PLUMED_REGISTER_ACTION(Fccubic,"FCCUBIC") -void Fccubic::registerKeywords( Keywords& keys ){ +void Fccubic::registerKeywords( Keywords& keys ) { CubicHarmonicBase::registerKeywords( keys ); keys.add("compulsory","ALPHA","3.0","The alpha parameter of the angular function"); } Fccubic::Fccubic(const ActionOptions&ao): -Action(ao), -CubicHarmonicBase(ao) + Action(ao), + CubicHarmonicBase(ao) { // Scaling factors such that '1' corresponds to fcc lattice // and '0' corresponds to isotropic (liquid) @@ -110,7 +110,7 @@ double Fccubic::calculateCubicHarmonic( const Vector& distance, const double& d2 double z2 = distance[2]*distance[2]; double z4 = z2*z2; - + double r8 = pow( d2, 4 ); double r12 = pow( d2, 6 ); @@ -119,12 +119,12 @@ double Fccubic::calculateCubicHarmonic( const Vector& distance, const double& d2 double t0 = (x2*y4+x2*z4)/r8-alpha*x2*y4*z4/r12; double t1 = (y2*x4+y2*z4)/r8-alpha*y2*x4*z4/r12; double t2 = (z2*x4+z2*y4)/r8-alpha*z2*x4*y4/r12; - double t3 = (2*tmp-alpha*x4*y4*z4/r12)/d2; - + double t3 = (2*tmp-alpha*x4*y4*z4/r12)/d2; + myder[0]=4*a1*distance[0]*(t0-t3); myder[1]=4*a1*distance[1]*(t1-t3); myder[2]=4*a1*distance[2]*(t2-t3); - + return a1*tmp+b1; } diff --git a/src/crystallization/Gradient.cpp b/src/crystallization/Gradient.cpp index 0c2f7c729..173d9e5ad 100644 --- a/src/crystallization/Gradient.cpp +++ b/src/crystallization/Gradient.cpp @@ -35,24 +35,24 @@ This command allows you to calculate the collective variable discussed in \cite \par Examples -The input below calculates the gradient of the density of atoms in the manner +The input below calculates the gradient of the density of atoms in the manner described in \cite fede-grad in order to detect whether or not atoms are distributed uniformly along the x-axis of the simulation cell. \verbatim -d1: DENSITY SPECIES=1-50 -s1: GRADIENT ORIGIN=1 DATA=d1 DIR=x NBINS=4 SIGMA=1.0 +d1: DENSITY SPECIES=1-50 +s1: GRADIENT ORIGIN=1 DATA=d1 DIR=x NBINS=4 SIGMA=1.0 PRINT ARG=s1 FILE=colvar \endverbatim The input below calculates the coordination numbers of the 50 atoms in the simulation cell. The gradient of this quantity is then evaluated in the manner described using the equation above -to detect whether the average values of the coordination number are uniformly distributed along the +to detect whether the average values of the coordination number are uniformly distributed along the x-axis of the simulation cell. \verbatim -d2: COORDINATIONNUMBER SPECIES=1-50 SWITCH={RATIONAL R_0=2.0} MORE_THAN={EXP R_0=4.0} -s2: GRADIENT ORIGIN=1 DATA=d2 DIR=x NBINS=4 SIGMA=1.0 +d2: COORDINATIONNUMBER SPECIES=1-50 SWITCH={RATIONAL R_0=2.0} MORE_THAN={EXP R_0=4.0} +s2: GRADIENT ORIGIN=1 DATA=d2 DIR=x NBINS=4 SIGMA=1.0 PRINT ARG=s2 FILE=colvar \endverbatim @@ -61,7 +61,7 @@ PRINT ARG=s2 FILE=colvar PLUMED_REGISTER_ACTION(Gradient,"GRADIENT") -void Gradient::registerKeywords( Keywords& keys ){ +void Gradient::registerKeywords( Keywords& keys ) { VolumeGradientBase::registerKeywords( keys ); keys.add("atoms","ORIGIN","we will use the position of this atom as the origin in our calculation"); keys.add("compulsory","DIR","xyz","the directions in which we are calculating the graident. Should be x, y, z, xy, xz, yz or xyz"); @@ -71,9 +71,9 @@ void Gradient::registerKeywords( Keywords& keys ){ } Gradient::Gradient(const ActionOptions&ao): -Action(ao), -VolumeGradientBase(ao), -nbins(3) + Action(ao), + VolumeGradientBase(ao), + nbins(3) { std::vector<AtomNumber> atom; parseAtomList("ORIGIN",atom); @@ -82,48 +82,48 @@ nbins(3) std::string direction; parse("DIR",direction); std::vector<unsigned> tbins; parseVector("NBINS",tbins); - for(unsigned i=0;i<tbins.size();++i){ - if( tbins[i]<2 ) error("Number of grid points should be greater than 1"); + for(unsigned i=0; i<tbins.size(); ++i) { + if( tbins[i]<2 ) error("Number of grid points should be greater than 1"); } - if( direction=="x" ){ - if( tbins.size()!=1 ) error("mismatch between number of bins and direction"); - nbins[0]=tbins[0]; nbins[1]=0; nbins[2]=0; - } else if( direction=="y" ){ - if( tbins.size()!=1 ) error("mismatch between number of bins and direction"); - nbins[0]=0; nbins[1]=tbins[0]; nbins[2]=0; - } else if( direction=="z" ){ - if( tbins.size()!=1 ) error("mismatch between number of bins and direction"); - nbins[0]=0; nbins[1]=0; nbins[2]=tbins[0]; - } else if( direction=="xy" ){ - if( tbins.size()!=2 ) error("mismatch between number of bins and direction"); - nbins[0]=tbins[0]; nbins[1]=tbins[1]; nbins[2]=0; - } else if( direction=="xz" ){ - if( tbins.size()!=2 ) error("mismatch between number of bins and direction"); - nbins[0]=tbins[0]; nbins[1]=0; nbins[2]=tbins[1]; - } else if( direction=="yz" ){ - if( tbins.size()!=2 ) error("mismatch between number of bins and direction"); - nbins[0]=0; nbins[1]=tbins[0]; nbins[2]=tbins[1]; - } else if( direction=="xyz" ){ - if( tbins.size()!=3 ) error("mismatch between number of bins and direction"); - nbins[0]=tbins[0]; nbins[1]=tbins[1]; nbins[2]=tbins[2]; + if( direction=="x" ) { + if( tbins.size()!=1 ) error("mismatch between number of bins and direction"); + nbins[0]=tbins[0]; nbins[1]=0; nbins[2]=0; + } else if( direction=="y" ) { + if( tbins.size()!=1 ) error("mismatch between number of bins and direction"); + nbins[0]=0; nbins[1]=tbins[0]; nbins[2]=0; + } else if( direction=="z" ) { + if( tbins.size()!=1 ) error("mismatch between number of bins and direction"); + nbins[0]=0; nbins[1]=0; nbins[2]=tbins[0]; + } else if( direction=="xy" ) { + if( tbins.size()!=2 ) error("mismatch between number of bins and direction"); + nbins[0]=tbins[0]; nbins[1]=tbins[1]; nbins[2]=0; + } else if( direction=="xz" ) { + if( tbins.size()!=2 ) error("mismatch between number of bins and direction"); + nbins[0]=tbins[0]; nbins[1]=0; nbins[2]=tbins[1]; + } else if( direction=="yz" ) { + if( tbins.size()!=2 ) error("mismatch between number of bins and direction"); + nbins[0]=0; nbins[1]=tbins[0]; nbins[2]=tbins[1]; + } else if( direction=="xyz" ) { + if( tbins.size()!=3 ) error("mismatch between number of bins and direction"); + nbins[0]=tbins[0]; nbins[1]=tbins[1]; nbins[2]=tbins[2]; } else { - error( direction + " is not valid gradient direction"); + error( direction + " is not valid gradient direction"); } // Find number of quantities if( getPntrToMultiColvar()->isDensity() ) vend=2; else if( getPntrToMultiColvar()->getNumberOfQuantities()==2 ) vend=2; - else vend = getPntrToMultiColvar()->getNumberOfQuantities(); + else vend = getPntrToMultiColvar()->getNumberOfQuantities(); nquantities = vend + nbins[0] + nbins[1] + nbins[2]; // Output some nice information std::string functype=getPntrToMultiColvar()->getName(); std::transform( functype.begin(), functype.end(), functype.begin(), tolower ); - log.printf(" calculating gradient of %s in %s direction \n",functype.c_str(), direction.c_str() ); + log.printf(" calculating gradient of %s in %s direction \n",functype.c_str(), direction.c_str() ); log<<" Bibliography:"<<plumed.cite("Giberti, Tribello and Parrinello, J. Chem. Theory Comput., 9, 2526 (2013)")<<"\n"; - parse("SIGMA",sigma); parse("KERNEL",kerneltype); + parse("SIGMA",sigma); parse("KERNEL",kerneltype); checkRead(); requestAtoms(atom); // And setup the vessel @@ -132,34 +132,34 @@ nbins(3) readVesselKeywords(); } -void Gradient::setupRegions(){ +void Gradient::setupRegions() { // if( !getPbc().isOrthorombic() ) error("cell must be orthorhombic when using gradient"); } void Gradient::calculateAllVolumes( const unsigned& curr, MultiValue& outvals ) const { // Setup the bead - HistogramBead bead; bead.isNotPeriodic(); bead.setKernelType( kerneltype ); + HistogramBead bead; bead.isNotPeriodic(); bead.setKernelType( kerneltype ); Vector cpos = pbcDistance( getPosition(0), getPntrToMultiColvar()->getCentralAtomPos( curr ) ); // Note we use the pbc from base multicolvar so that we get numerical derivatives correct - Vector oderiv, fpos = (getPntrToMultiColvar()->getPbc()).realToScaled( cpos ); - + Vector oderiv, fpos = (getPntrToMultiColvar()->getPbc()).realToScaled( cpos ); + Vector deriv; unsigned nbase=vend; std::vector<Vector> refder(1); Tensor vir; vir.zero(); - for(unsigned idir=0;idir<3;++idir){ - deriv[0]=deriv[1]=deriv[2]=0.0; - double delx = 1.0 / static_cast<double>( nbins[idir] ); - for(unsigned jbead=0;jbead<nbins[idir];++jbead){ - // Calculate what box we are in - bead.set( -0.5+jbead*delx, -0.5+(jbead+1)*delx, sigma ); - double weight=bead.calculate( fpos[0], deriv[idir] ); - oderiv = (getPntrToMultiColvar()->getPbc()).realToScaled( deriv ); - // Set and derivatives - refder[0]=-oderiv; // vir = -Tensor(cpos,oderiv); - setNumberInVolume( nbase+jbead, curr, weight, oderiv, vir, refder, outvals ); + for(unsigned idir=0; idir<3; ++idir) { + deriv[0]=deriv[1]=deriv[2]=0.0; + double delx = 1.0 / static_cast<double>( nbins[idir] ); + for(unsigned jbead=0; jbead<nbins[idir]; ++jbead) { + // Calculate what box we are in + bead.set( -0.5+jbead*delx, -0.5+(jbead+1)*delx, sigma ); + double weight=bead.calculate( fpos[0], deriv[idir] ); + oderiv = (getPntrToMultiColvar()->getPbc()).realToScaled( deriv ); + // Set and derivatives + refder[0]=-oderiv; // vir = -Tensor(cpos,oderiv); + setNumberInVolume( nbase+jbead, curr, weight, oderiv, vir, refder, outvals ); // addReferenceAtomDerivatives( nbase+jbead, 0, -oderiv ); // addBoxDerivatives( nbase+jbead, -Tensor(cpos,oderiv) ); - } - nbase += nbins[idir]; + } + nbase += nbins[idir]; } } diff --git a/src/crystallization/Gradient.h b/src/crystallization/Gradient.h index bb3b81bd7..e639a8458 100644 --- a/src/crystallization/Gradient.h +++ b/src/crystallization/Gradient.h @@ -28,7 +28,7 @@ namespace PLMD { namespace crystallization { class Gradient : public multicolvar::VolumeGradientBase { -friend class GradientVessel; + friend class GradientVessel; private: /// The value of sigma double sigma; @@ -52,7 +52,7 @@ public: inline unsigned Gradient::getNumberOfQuantities() const { return nquantities; -} +} } } diff --git a/src/crystallization/GradientVessel.cpp b/src/crystallization/GradientVessel.cpp index d1ad12fe9..a266bbf01 100644 --- a/src/crystallization/GradientVessel.cpp +++ b/src/crystallization/GradientVessel.cpp @@ -46,55 +46,55 @@ public: PLUMED_REGISTER_VESSEL(GradientVessel,"GRADIENT") -void GradientVessel::registerKeywords( Keywords& keys ){ +void GradientVessel::registerKeywords( Keywords& keys ) { vesselbase::FunctionVessel::registerKeywords(keys); } -void GradientVessel::reserveKeyword( Keywords& keys ){ +void GradientVessel::reserveKeyword( Keywords& keys ) { keys.reserve("vessel","GRADIENT","calculate the gradient"); keys.addOutputComponent("gradient","GRADIENT","the gradient"); } GradientVessel::GradientVessel( const vesselbase::VesselOptions& da ) : -FunctionVessel(da) + FunctionVessel(da) { - Gradient* vg=dynamic_cast<Gradient*>( getAction() ); - plumed_assert( vg ); isdens=(vg->getPntrToMultiColvar())->isDensity(); - nweights = vg->nbins[0] + vg->nbins[1] + vg->nbins[2]; - if( (vg->getPntrToMultiColvar())->getNumberOfQuantities()>2 ){ - ncomponents = (vg->getPntrToMultiColvar())->getNumberOfQuantities() - 2; - } else { - ncomponents = 1; - } - - starts.push_back(0); - if( vg->nbins[0]>0 ){ - starts.push_back( vg->nbins[0] ); - if( vg->nbins[1]>0 ){ - starts.push_back( vg->nbins[0] + vg->nbins[1] ); - if( vg->nbins[2]>0 ) starts.push_back( nweights ); - } else if( vg->nbins[2]>0 ){ - starts.push_back( nweights ); - } - } else if( vg->nbins[1]>0 ){ - starts.push_back( vg->nbins[1] ); - if( vg->nbins[2]>0 ) starts.push_back( nweights ); - } else if( vg->nbins[2]>0 ){ - starts.push_back( nweights ); - } + Gradient* vg=dynamic_cast<Gradient*>( getAction() ); + plumed_assert( vg ); isdens=(vg->getPntrToMultiColvar())->isDensity(); + nweights = vg->nbins[0] + vg->nbins[1] + vg->nbins[2]; + if( (vg->getPntrToMultiColvar())->getNumberOfQuantities()>2 ) { + ncomponents = (vg->getPntrToMultiColvar())->getNumberOfQuantities() - 2; + } else { + ncomponents = 1; + } + + starts.push_back(0); + if( vg->nbins[0]>0 ) { + starts.push_back( vg->nbins[0] ); + if( vg->nbins[1]>0 ) { + starts.push_back( vg->nbins[0] + vg->nbins[1] ); + if( vg->nbins[2]>0 ) starts.push_back( nweights ); + } else if( vg->nbins[2]>0 ) { + starts.push_back( nweights ); + } + } else if( vg->nbins[1]>0 ) { + starts.push_back( vg->nbins[1] ); + if( vg->nbins[2]>0 ) starts.push_back( nweights ); + } else if( vg->nbins[2]>0 ) { + starts.push_back( nweights ); + } } -std::string GradientVessel::value_descriptor(){ +std::string GradientVessel::value_descriptor() { return "the gradient"; } -void GradientVessel::resize(){ - if( getAction()->derivativesAreRequired() ){ - unsigned nder=getAction()->getNumberOfDerivatives(); - resizeBuffer( (1+nder)*(ncomponents+1)*nweights ); - getFinalValue()->resizeDerivatives( nder ); +void GradientVessel::resize() { + if( getAction()->derivativesAreRequired() ) { + unsigned nder=getAction()->getNumberOfDerivatives(); + resizeBuffer( (1+nder)*(ncomponents+1)*nweights ); + getFinalValue()->resizeDerivatives( nder ); } else { - resizeBuffer( (ncomponents+1)*nweights ); + resizeBuffer( (ncomponents+1)*nweights ); } } @@ -102,90 +102,90 @@ void GradientVessel::calculate( const unsigned& current, MultiValue& myvals, std unsigned nder; if( getAction()->derivativesAreRequired() ) nder=getAction()->getNumberOfDerivatives(); else nder=0; - unsigned wstart, cstart; if( ncomponents==1 ){ cstart=1; wstart=2; } else { cstart=2; wstart=2+ncomponents; } - - for(unsigned iw=0;iw<nweights;++iw){ - unsigned xx = (ncomponents+1)*iw; - double weight=myvals.get(wstart+iw); - buffer[bufstart+xx*(nder+1)] += weight; - myvals.chainRule( wstart + iw, xx, 1, 0, 1.0, bufstart, buffer ); - for(unsigned jc=0;jc<ncomponents;++jc){ - double colvar=myvals.get( cstart + jc ); - buffer[bufstart+(xx+1+jc)*(nder+1) ] += weight*colvar; - myvals.chainRule( cstart + jc, xx + 1 + jc, 1, 0, weight, bufstart, buffer ); - myvals.chainRule( wstart + iw, xx + 1 + jc, 1, 0, colvar, bufstart, buffer ); - } + unsigned wstart, cstart; if( ncomponents==1 ) { cstart=1; wstart=2; } else { cstart=2; wstart=2+ncomponents; } + + for(unsigned iw=0; iw<nweights; ++iw) { + unsigned xx = (ncomponents+1)*iw; + double weight=myvals.get(wstart+iw); + buffer[bufstart+xx*(nder+1)] += weight; + myvals.chainRule( wstart + iw, xx, 1, 0, 1.0, bufstart, buffer ); + for(unsigned jc=0; jc<ncomponents; ++jc) { + double colvar=myvals.get( cstart + jc ); + buffer[bufstart+(xx+1+jc)*(nder+1) ] += weight*colvar; + myvals.chainRule( cstart + jc, xx + 1 + jc, 1, 0, weight, bufstart, buffer ); + myvals.chainRule( wstart + iw, xx + 1 + jc, 1, 0, colvar, bufstart, buffer ); + } } } -void GradientVessel::finish( const std::vector<double>& buffer ){ +void GradientVessel::finish( const std::vector<double>& buffer ) { std::vector<double> val_interm( ncomponents*nweights ); unsigned nder; if( getAction()->derivativesAreRequired() ) nder=getAction()->getNumberOfDerivatives(); else nder=0; Matrix<double> der_interm( ncomponents*nweights, nder ); der_interm=0; - if( isdens ){ - for(unsigned iw=0;iw<nweights;++iw){ - val_interm[iw] = buffer[bufstart + 2*iw*(1+nder)]; - if( getAction()->derivativesAreRequired() ){ - unsigned wstart = bufstart + 2*iw*(nder+1) + 1; - for(unsigned jder=0;jder<nder;++jder) der_interm( iw, jder ) += buffer[ wstart + jder ]; - } + if( isdens ) { + for(unsigned iw=0; iw<nweights; ++iw) { + val_interm[iw] = buffer[bufstart + 2*iw*(1+nder)]; + if( getAction()->derivativesAreRequired() ) { + unsigned wstart = bufstart + 2*iw*(nder+1) + 1; + for(unsigned jder=0; jder<nder; ++jder) der_interm( iw, jder ) += buffer[ wstart + jder ]; } + } } else { - for(unsigned iw=0;iw<nweights;++iw){ - unsigned xx = (ncomponents+1)*iw; - double ww=buffer[bufstart + xx*(1+nder)]; - for(unsigned jc=0;jc<ncomponents;++jc) val_interm[ iw*ncomponents + jc ] = buffer[bufstart + (xx+1+jc)*(1+nder)] / ww; - if( getAction()->derivativesAreRequired() ){ - unsigned wstart = bufstart + xx*(nder+1) + 1; - for(unsigned jc=0;jc<ncomponents;++jc){ - unsigned bstart = bufstart + ( xx + 1 + jc )*(nder+1) + 1; - double val = buffer[bufstart + (nder+1)*(xx+1+jc)]; - for(unsigned jder=0;jder<nder;++jder) - der_interm( iw*ncomponents + jc, jder ) = (1.0/ww)*buffer[bstart + jder] - (val/(ww*ww))*buffer[wstart + jder]; - } - } + for(unsigned iw=0; iw<nweights; ++iw) { + unsigned xx = (ncomponents+1)*iw; + double ww=buffer[bufstart + xx*(1+nder)]; + for(unsigned jc=0; jc<ncomponents; ++jc) val_interm[ iw*ncomponents + jc ] = buffer[bufstart + (xx+1+jc)*(1+nder)] / ww; + if( getAction()->derivativesAreRequired() ) { + unsigned wstart = bufstart + xx*(nder+1) + 1; + for(unsigned jc=0; jc<ncomponents; ++jc) { + unsigned bstart = bufstart + ( xx + 1 + jc )*(nder+1) + 1; + double val = buffer[bufstart + (nder+1)*(xx+1+jc)]; + for(unsigned jder=0; jder<nder; ++jder) + der_interm( iw*ncomponents + jc, jder ) = (1.0/ww)*buffer[bstart + jder] - (val/(ww*ww))*buffer[wstart + jder]; + } } + } } - double tmp, diff2=0.0; - - if( getAction()->derivativesAreRequired() ){ - Value* fval=getFinalValue(); - for(unsigned j=0;j<starts.size()-1;++j){ - for(unsigned bin=starts[j];bin<starts[j+1];++bin){ - for(unsigned jc=0;jc<ncomponents;++jc){ - if( bin==starts[j] ){ - tmp=val_interm[(starts[j+1]-1)*ncomponents + jc] - val_interm[bin*ncomponents + jc]; - for(unsigned jder=0;jder<nder;++jder){ - fval->addDerivative( jder, +2.0*tmp*der_interm( (starts[j+1]-1)*ncomponents + jc, jder) ); - fval->addDerivative( jder, -2.0*tmp*der_interm( bin*ncomponents + jc, jder ) ); - } - } else { - tmp=val_interm[(bin-1)*ncomponents + jc] - val_interm[bin*ncomponents + jc]; - for(unsigned jder=0;jder<nder;++jder){ - fval->addDerivative( jder, +2.0*tmp*der_interm( (bin-1)*ncomponents + jc, jder) ); - fval->addDerivative( jder, -2.0*tmp*der_interm( bin*ncomponents + jc, jder ) ); - } - } - diff2+=tmp*tmp; - } + double tmp, diff2=0.0; + + if( getAction()->derivativesAreRequired() ) { + Value* fval=getFinalValue(); + for(unsigned j=0; j<starts.size()-1; ++j) { + for(unsigned bin=starts[j]; bin<starts[j+1]; ++bin) { + for(unsigned jc=0; jc<ncomponents; ++jc) { + if( bin==starts[j] ) { + tmp=val_interm[(starts[j+1]-1)*ncomponents + jc] - val_interm[bin*ncomponents + jc]; + for(unsigned jder=0; jder<nder; ++jder) { + fval->addDerivative( jder, +2.0*tmp*der_interm( (starts[j+1]-1)*ncomponents + jc, jder) ); + fval->addDerivative( jder, -2.0*tmp*der_interm( bin*ncomponents + jc, jder ) ); + } + } else { + tmp=val_interm[(bin-1)*ncomponents + jc] - val_interm[bin*ncomponents + jc]; + for(unsigned jder=0; jder<nder; ++jder) { + fval->addDerivative( jder, +2.0*tmp*der_interm( (bin-1)*ncomponents + jc, jder) ); + fval->addDerivative( jder, -2.0*tmp*der_interm( bin*ncomponents + jc, jder ) ); + } + } + diff2+=tmp*tmp; } - } + } + } } else { - for(unsigned j=0;j<starts.size()-1;++j){ - for(unsigned bin=starts[j];bin<starts[j+1];++bin){ - for(unsigned jc=0;jc<ncomponents;++jc){ - if( bin==starts[j] ) tmp=val_interm[(starts[j+1]-1)*ncomponents + jc] - val_interm[bin*ncomponents + jc]; - else tmp=val_interm[(bin-1)*ncomponents + jc] - val_interm[bin*ncomponents + jc]; - diff2+=tmp*tmp; - } + for(unsigned j=0; j<starts.size()-1; ++j) { + for(unsigned bin=starts[j]; bin<starts[j+1]; ++bin) { + for(unsigned jc=0; jc<ncomponents; ++jc) { + if( bin==starts[j] ) tmp=val_interm[(starts[j+1]-1)*ncomponents + jc] - val_interm[bin*ncomponents + jc]; + else tmp=val_interm[(bin-1)*ncomponents + jc] - val_interm[bin*ncomponents + jc]; + diff2+=tmp*tmp; } - } + } + } } - setOutputValue( diff2 ); + setOutputValue( diff2 ); } } diff --git a/src/crystallization/InterMolecularTorsions.cpp b/src/crystallization/InterMolecularTorsions.cpp index 62094eb8a..3839e094d 100644 --- a/src/crystallization/InterMolecularTorsions.cpp +++ b/src/crystallization/InterMolecularTorsions.cpp @@ -23,8 +23,8 @@ #include "multicolvar/AtomValuePack.h" #include "core/ActionRegister.h" #include "tools/SwitchingFunction.h" -#include "tools/Torsion.h" - +#include "tools/Torsion.h" + #include <string> #include <cmath> @@ -43,32 +43,32 @@ Here the sums run over all pairs of molecules. \f$\sigma(r_{ij})\f$ is a \ref sw action on the distance between the centers of molecules \f$i\f$ and \f$j\f$. \f$\theta_{ij}\f$ is then the torsional angle between an orientation vector for molecule \f$i\f$ and molecule \f$j\f$. -This command can be used to calculate the intermolecular torsional angles between the orientations of nearby molecules. The orientation of a -molecule can be calculated by using either the \ref MOLECULES or the \ref PLANES commands. These two commands calculate the orientation of a -bond in the molecule or the orientation of a plane containing three of the molecule's atoms. Furthermore, when we use these commands we think of +This command can be used to calculate the intermolecular torsional angles between the orientations of nearby molecules. The orientation of a +molecule can be calculated by using either the \ref MOLECULES or the \ref PLANES commands. These two commands calculate the orientation of a +bond in the molecule or the orientation of a plane containing three of the molecule's atoms. Furthermore, when we use these commands we think of molecules as objects that lie at a point in space and that have an orientation. This command calculates the torsional angles between the orientations -of these objects. We can then calculates functions of a large number of these torsional angles that measures things such as the number of torsional -angles that are within a particular range. Because it is often useful to only consider the torsional angles between objects that are within a certain +of these objects. We can then calculates functions of a large number of these torsional angles that measures things such as the number of torsional +angles that are within a particular range. Because it is often useful to only consider the torsional angles between objects that are within a certain distance of each other we can, when calculating these sums, perform a weighted sum and use a \ref switchingfunction to ensure that we focus on molecules -that are close together. +that are close together. \par Examples The example input below is necessarily but gives you an idea of what can be achieved using this action. -The orientations and positions of four molecules are defined using the \ref MOLECULES action as the position of the +The orientations and positions of four molecules are defined using the \ref MOLECULES action as the position of the centeres of mass of the two atoms specified and the direction of the vector connecting the two atoms that were specified. The torsional angles between the molecules are then calculated by the \ref INTERMOLECULARTORSIONS command labelled tt_p. We then compute a \ref HISTOGRAM that shows the distribution that these torsional angles take in the structure. The weight a given torsional angle contributes to this \ref HISTOGRAM is determined using a \ref switchingfunction that acts on the distance -between the two molecules. As such the torsional angles between molecules that are close together contribute a high weight to the -histogram while the torsional angles between molecules that are far apart does not contribute to the histogram. The histogram is +between the two molecules. As such the torsional angles between molecules that are close together contribute a high weight to the +histogram while the torsional angles between molecules that are far apart does not contribute to the histogram. The histogram is averaged over the whole trajectory and output once all the trajectory frames have been read. \verbatim m1: MOLECULES MOL1=1,2 MOL2=3,4 MOL3=5,6 MOL4=7,8 -tt_p: INTERMOLECULARTORSIONS MOLS=m1 SWITCH={RATIONAL R_0=0.25 D_0=2.0 D_MAX=3.0} -htt_p: HISTOGRAM DATA=tt_p GRID_MIN=-pi GRID_MAX=pi BANDWIDTH=0.1 GRID_BIN=200 STRIDE=1 -DUMPGRID GRID=htt_p FILE=myhist.out +tt_p: INTERMOLECULARTORSIONS MOLS=m1 SWITCH={RATIONAL R_0=0.25 D_0=2.0 D_MAX=3.0} +htt_p: HISTOGRAM DATA=tt_p GRID_MIN=-pi GRID_MAX=pi BANDWIDTH=0.1 GRID_BIN=200 STRIDE=1 +DUMPGRID GRID=htt_p FILE=myhist.out \endverbatim */ @@ -89,57 +89,57 @@ public: /// Actually do the calculation double compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ) const ; /// Is the variable periodic - bool isPeriodic(){ return true; } - void retrieveDomain( std::string& min, std::string& max ){ min="-pi"; max="+pi"; } + bool isPeriodic() { return true; } + void retrieveDomain( std::string& min, std::string& max ) { min="-pi"; max="+pi"; } }; PLUMED_REGISTER_ACTION(InterMolecularTorsions,"INTERMOLECULARTORSIONS") -void InterMolecularTorsions::registerKeywords( Keywords& keys ){ +void InterMolecularTorsions::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); keys.add("atoms","MOLS","The molecules you would like to calculate the torsional angles between. This should be the label/s of \\ref MOLECULES or \\ref PLANES actions"); - keys.add("atoms-1","MOLSA","In this version of the input the torsional angles between all pairs of atoms including one atom from MOLA one atom from MOLB will be computed. " - "This should be the label/s of \\ref MOLECULES or \\ref PLANES actions"); + keys.add("atoms-1","MOLSA","In this version of the input the torsional angles between all pairs of atoms including one atom from MOLA one atom from MOLB will be computed. " + "This should be the label/s of \\ref MOLECULES or \\ref PLANES actions"); keys.add("atoms-1","MOLSB","In this version of the input the torsional angles between all pairs of atoms including one atom from MOLA one atom from MOLB will be computed. " - "This should be the label/s of \\ref MOLECULES or \\ref PLANES actions"); + "This should be the label/s of \\ref MOLECULES or \\ref PLANES actions"); keys.add("compulsory","NN","6","The n parameter of the switching function "); keys.add("compulsory","MM","0","The m parameter of the switching function; 0 implies 2*NN"); keys.add("compulsory","D_0","0.0","The d_0 parameter of the switching function"); keys.add("compulsory","R_0","The r_0 parameter of the switching function"); keys.add("optional","SWITCH","This keyword is used if you want to employ an alternative to the continuous swiching function defined above. " - "The following provides information on the \\ref switchingfunction that are available. " - "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); + "The following provides information on the \\ref switchingfunction that are available. " + "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); // Use actionWithDistributionKeywords - keys.remove("LOWMEM"); + keys.remove("LOWMEM"); keys.addFlag("LOWMEM",false,"lower the memory requirements"); } InterMolecularTorsions::InterMolecularTorsions(const ActionOptions& ao): -Action(ao), -MultiColvarBase(ao) + Action(ao), + MultiColvarBase(ao) { - for(unsigned i=0;i<getNumberOfBaseMultiColvars();++i){ - if( getBaseMultiColvar(i)->getNumberOfQuantities()!=5 ) error("input multicolvar does not calculate molecular orientations"); + for(unsigned i=0; i<getNumberOfBaseMultiColvars(); ++i) { + if( getBaseMultiColvar(i)->getNumberOfQuantities()!=5 ) error("input multicolvar does not calculate molecular orientations"); } // The weight of this does have derivatives weightHasDerivatives=true; // Read in the switching function std::string sw, errors; parse("SWITCH",sw); - if(sw.length()>0){ - switchingFunction.set(sw,errors); + if(sw.length()>0) { + switchingFunction.set(sw,errors); } else { - double r_0=-1.0, d_0; int nn, mm; - parse("NN",nn); parse("MM",mm); - parse("R_0",r_0); parse("D_0",d_0); - if( r_0<0.0 ) error("you must set a value for R_0"); - switchingFunction.set(nn,mm,r_0,d_0); + double r_0=-1.0, d_0; int nn, mm; + parse("NN",nn); parse("MM",mm); + parse("R_0",r_0); parse("D_0",d_0); + if( r_0<0.0 ) error("you must set a value for R_0"); + switchingFunction.set(nn,mm,r_0,d_0); } log.printf(" calculating number of links with atoms separation of %s\n",( switchingFunction.description() ).c_str() ); std::vector<AtomNumber> all_atoms; readTwoGroups( "MOLS", "MOLSA", "MOLSB", all_atoms ); setupMultiColvarBase( all_atoms ); setLinkCellCutoff( switchingFunction.get_dmax() ); - for(unsigned i=0;i<getNumberOfBaseMultiColvars();++i){ + for(unsigned i=0; i<getNumberOfBaseMultiColvars(); ++i) { if( !getBaseMultiColvar(i)->hasDifferentiableOrientation() ) error("cannot use multicolvar of type " + getBaseMultiColvar(i)->getName() ); } @@ -154,39 +154,39 @@ double InterMolecularTorsions::calculateWeight( const unsigned& taskCode, const Vector distance = getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); double dfunc, sw = switchingFunction.calculateSqr( distance.modulo2(), dfunc ); - if( !doNotCalculateDerivatives() ){ - addAtomDerivatives( 0, 0, (-dfunc)*weight*distance, myatoms ); - addAtomDerivatives( 0, 1, (dfunc)*weight*distance, myatoms ); - myatoms.addBoxDerivatives( 0, (-dfunc)*weight*Tensor(distance,distance) ); + if( !doNotCalculateDerivatives() ) { + addAtomDerivatives( 0, 0, (-dfunc)*weight*distance, myatoms ); + addAtomDerivatives( 0, 1, (dfunc)*weight*distance, myatoms ); + myatoms.addBoxDerivatives( 0, (-dfunc)*weight*Tensor(distance,distance) ); } return sw; } double InterMolecularTorsions::compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ) const { - Vector v1, v2, dv1, dv2, dconn, conn = getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); - - // Retrieve vectors - std::vector<double> orient0( 5 ), orient1( 5 ); - getInputData( 0, true, myatoms, orient0 ); - getInputData( 1, true, myatoms, orient1 ); - for(unsigned i=0;i<3;++i){ v1[i]=orient0[2+i]; v2[i]=orient1[2+i]; } - if( getBaseMultiColvar(0)->getNumberOfQuantities()<3 ) return 1.0; - - // Evaluate angle - Torsion t; double angle = t.compute( v1, conn, v2, dv1, dconn, dv2 ); - for(unsigned i=0;i<3;++i){ orient0[i+2]=dv1[i]; orient1[i+2]=dv2[i]; } - - // And accumulate derivatives - if( !doNotCalculateDerivatives() ){ - MultiValue& myder0=getInputDerivatives( 0, true, myatoms ); - mergeInputDerivatives( 1, 2, orient1.size(), 0, orient0, myder0, myatoms ); - MultiValue& myder1=getInputDerivatives( 1, true, myatoms ); - mergeInputDerivatives( 1, 2, orient0.size(), 1, orient1, myder1, myatoms ); - addAtomDerivatives( 1, 0, -dconn, myatoms ); addAtomDerivatives( 1, 1, dconn, myatoms ); - myatoms.addBoxDerivatives( 1, -extProduct( conn, dconn ) ); - } - - return angle; + Vector v1, v2, dv1, dv2, dconn, conn = getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); + + // Retrieve vectors + std::vector<double> orient0( 5 ), orient1( 5 ); + getInputData( 0, true, myatoms, orient0 ); + getInputData( 1, true, myatoms, orient1 ); + for(unsigned i=0; i<3; ++i) { v1[i]=orient0[2+i]; v2[i]=orient1[2+i]; } + if( getBaseMultiColvar(0)->getNumberOfQuantities()<3 ) return 1.0; + + // Evaluate angle + Torsion t; double angle = t.compute( v1, conn, v2, dv1, dconn, dv2 ); + for(unsigned i=0; i<3; ++i) { orient0[i+2]=dv1[i]; orient1[i+2]=dv2[i]; } + + // And accumulate derivatives + if( !doNotCalculateDerivatives() ) { + MultiValue& myder0=getInputDerivatives( 0, true, myatoms ); + mergeInputDerivatives( 1, 2, orient1.size(), 0, orient0, myder0, myatoms ); + MultiValue& myder1=getInputDerivatives( 1, true, myatoms ); + mergeInputDerivatives( 1, 2, orient0.size(), 1, orient1, myder1, myatoms ); + addAtomDerivatives( 1, 0, -dconn, myatoms ); addAtomDerivatives( 1, 1, dconn, myatoms ); + myatoms.addBoxDerivatives( 1, -extProduct( conn, dconn ) ); + } + + return angle; } } diff --git a/src/crystallization/LocalSteinhardt.h b/src/crystallization/LocalSteinhardt.h index a71c6e65e..c7ced6ab3 100644 --- a/src/crystallization/LocalSteinhardt.h +++ b/src/crystallization/LocalSteinhardt.h @@ -29,31 +29,31 @@ namespace crystallization { template<class T> class LocalSteinhardt : public OrientationSphere { public: - static void registerKeywords( Keywords& keys ){ + static void registerKeywords( Keywords& keys ) { OrientationSphere::registerKeywords(keys); } explicit LocalSteinhardt(const ActionOptions& ao): Action(ao), OrientationSphere(ao) { - for(unsigned i=0;i<getNumberOfBaseMultiColvars();++i){ - T* mc=dynamic_cast<T*>( getBaseMultiColvar(i) ); - if(!mc){ - if( getBaseMultiColvar(i)->getNumberOfBaseMultiColvars()==0 ){ - error("input action is not calculating the correct vectors"); - } - for(unsigned j=0;j<getBaseMultiColvar(i)->getNumberOfBaseMultiColvars();++j){ - T* mmc=dynamic_cast<T*>( getBaseMultiColvar(i)->getBaseMultiColvar(j) ); - if( !mmc ) error("input action is not calculating the correct vectors"); - } - } - } + for(unsigned i=0; i<getNumberOfBaseMultiColvars(); ++i) { + T* mc=dynamic_cast<T*>( getBaseMultiColvar(i) ); + if(!mc) { + if( getBaseMultiColvar(i)->getNumberOfBaseMultiColvars()==0 ) { + error("input action is not calculating the correct vectors"); + } + for(unsigned j=0; j<getBaseMultiColvar(i)->getNumberOfBaseMultiColvars(); ++j) { + T* mmc=dynamic_cast<T*>( getBaseMultiColvar(i)->getBaseMultiColvar(j) ); + if( !mmc ) error("input action is not calculating the correct vectors"); + } + } + } } double computeVectorFunction( const Vector& conn, const std::vector<double>& vec1, const std::vector<double>& vec2, Vector& dconn, std::vector<double>& dvec1, std::vector<double>& dvec2 ) const { - double dot=0; dconn.zero(); - for(unsigned k=2;k<vec1.size();++k){ - dot+=vec1[k]*vec2[k]; dvec1[k]=vec2[k]; dvec2[k]=vec1[k]; - } - return dot; + double dot=0; dconn.zero(); + for(unsigned k=2; k<vec1.size(); ++k) { + dot+=vec1[k]*vec2[k]; dvec1[k]=vec2[k]; dvec2[k]=vec1[k]; + } + return dot; } }; diff --git a/src/crystallization/MoleculeOrientation.cpp b/src/crystallization/MoleculeOrientation.cpp index b0e510a28..5bade7022 100644 --- a/src/crystallization/MoleculeOrientation.cpp +++ b/src/crystallization/MoleculeOrientation.cpp @@ -29,7 +29,7 @@ namespace crystallization { /* Calculate the vectors connecting a pair of atoms in order to represent the orientation of a molecule. -At its simplest this command can be used to calculate the average length of an internal vector in a +At its simplest this command can be used to calculate the average length of an internal vector in a collection of different molecules. When used in conjunction with MutiColvarFunctions in can be used to do a variety of more complex tasks. @@ -63,31 +63,31 @@ public: PLUMED_REGISTER_ACTION(MoleculeOrientation,"MOLECULES") -void MoleculeOrientation::registerKeywords( Keywords& keys ){ +void MoleculeOrientation::registerKeywords( Keywords& keys ) { VectorMultiColvar::registerKeywords( keys ); keys.use("VMEAN"); - keys.add("numbered","MOL","The numerical indices of the atoms in the molecule. The orientation of the molecule is equal to " - "the vector connecting the first two atoms specified. If a third atom is specified its position " - "is used to specify where the molecule is. If a third atom is not present the molecule is assumed " - "to be at the center of the vector connecting the first two atoms."); - keys.reset_style("MOL","atoms"); + keys.add("numbered","MOL","The numerical indices of the atoms in the molecule. The orientation of the molecule is equal to " + "the vector connecting the first two atoms specified. If a third atom is specified its position " + "is used to specify where the molecule is. If a third atom is not present the molecule is assumed " + "to be at the center of the vector connecting the first two atoms."); + keys.reset_style("MOL","atoms"); } MoleculeOrientation::MoleculeOrientation( const ActionOptions& ao ): -Action(ao), -VectorMultiColvar(ao) + Action(ao), + VectorMultiColvar(ao) { std::vector<AtomNumber> all_atoms; - readAtomsLikeKeyword("MOL",-1,all_atoms); + readAtomsLikeKeyword("MOL",-1,all_atoms); nvectors = std::floor( ablocks.size() / 2 ); if( ablocks.size()%2!=0 && 2*nvectors+1!=ablocks.size() ) error("number of atoms in molecule specification is wrong. Should be two or three."); if( all_atoms.size()==0 ) error("No atoms were specified"); setVectorDimensionality( 3*nvectors ); setupMultiColvarBase( all_atoms ); - if( ablocks.size()==2*nvectors+1 ){ + if( ablocks.size()==2*nvectors+1 ) { std::vector<bool> catom_ind(ablocks.size(), false); catom_ind[ablocks.size()-1]=true; setAtomsForCentralAtom( catom_ind ); - } + } } AtomNumber MoleculeOrientation::getAbsoluteIndexOfCentralAtom( const unsigned& iatom ) const { @@ -97,55 +97,55 @@ AtomNumber MoleculeOrientation::getAbsoluteIndexOfCentralAtom( const unsigned& i } void MoleculeOrientation::calculateVector( multicolvar::AtomValuePack& myatoms ) const { - for(unsigned i=0;i<nvectors;++i){ - Vector distance; distance=getSeparation( myatoms.getPosition(2*i+0), myatoms.getPosition(2*i+1) ); - - addAtomDerivatives( 2+3*i+0, 2*i+0, Vector(-1.0,0,0), myatoms ); - addAtomDerivatives( 2+3*i+0, 2*i+1, Vector(+1.0,0,0), myatoms ); - myatoms.addBoxDerivatives( 2+3*i+0, Tensor(distance,Vector(-1.0,0,0)) ); - myatoms.addValue( 2+3*i+0, distance[0] ); - - addAtomDerivatives( 2+3*i+1, 2*i+0, Vector(0,-1.0,0), myatoms ); - addAtomDerivatives( 2+3*i+1, 2*i+1, Vector(0,+1.0,0), myatoms ); - myatoms.addBoxDerivatives( 2+3*i+1, Tensor(distance,Vector(0,-1.0,0)) ); - myatoms.addValue( 2+3*i+1, distance[1] ); - - addAtomDerivatives( 2+3*i+2, 2*i+0, Vector(0,0,-1.0), myatoms ); - addAtomDerivatives( 2+3*i+2, 2*i+1, Vector(0,0,+1.0), myatoms ); - myatoms.addBoxDerivatives( 2+3*i+2, Tensor(distance,Vector(0,0,-1.0)) ); - myatoms.addValue( 2+3*i+2, distance[2] ); - } + for(unsigned i=0; i<nvectors; ++i) { + Vector distance; distance=getSeparation( myatoms.getPosition(2*i+0), myatoms.getPosition(2*i+1) ); + + addAtomDerivatives( 2+3*i+0, 2*i+0, Vector(-1.0,0,0), myatoms ); + addAtomDerivatives( 2+3*i+0, 2*i+1, Vector(+1.0,0,0), myatoms ); + myatoms.addBoxDerivatives( 2+3*i+0, Tensor(distance,Vector(-1.0,0,0)) ); + myatoms.addValue( 2+3*i+0, distance[0] ); + + addAtomDerivatives( 2+3*i+1, 2*i+0, Vector(0,-1.0,0), myatoms ); + addAtomDerivatives( 2+3*i+1, 2*i+1, Vector(0,+1.0,0), myatoms ); + myatoms.addBoxDerivatives( 2+3*i+1, Tensor(distance,Vector(0,-1.0,0)) ); + myatoms.addValue( 2+3*i+1, distance[1] ); + + addAtomDerivatives( 2+3*i+2, 2*i+0, Vector(0,0,-1.0), myatoms ); + addAtomDerivatives( 2+3*i+2, 2*i+1, Vector(0,0,+1.0), myatoms ); + myatoms.addBoxDerivatives( 2+3*i+2, Tensor(distance,Vector(0,0,-1.0)) ); + myatoms.addValue( 2+3*i+2, distance[2] ); + } } -void MoleculeOrientation::normalizeVector( std::vector<double>& vals ) const { - for(unsigned i=0;i<nvectors;++i){ - double norm=0; - for(unsigned j=0;j<3;++j) norm += vals[2+3*i+j]*vals[2+3*i+j]; - norm = sqrt(norm); - - double inorm = 1.0; if( norm>epsilon ) inorm = 1.0 / norm; - for(unsigned j=0;j<3;++j) vals[2+3*i+j] = inorm*vals[2+3*i+j]; +void MoleculeOrientation::normalizeVector( std::vector<double>& vals ) const { + for(unsigned i=0; i<nvectors; ++i) { + double norm=0; + for(unsigned j=0; j<3; ++j) norm += vals[2+3*i+j]*vals[2+3*i+j]; + norm = sqrt(norm); + + double inorm = 1.0; if( norm>epsilon ) inorm = 1.0 / norm; + for(unsigned j=0; j<3; ++j) vals[2+3*i+j] = inorm*vals[2+3*i+j]; } } void MoleculeOrientation::normalizeVectorDerivatives( MultiValue& myvals ) const { std::vector<double> weight( nvectors ), wdf( nvectors ); - for(unsigned ivec=0;ivec<nvectors;++ivec){ - double v=0; for(unsigned jcomp=0;jcomp<3;++jcomp) v += myvals.get( 2+3*ivec+jcomp )*myvals.get( 2+3*ivec+jcomp ); - v=sqrt(v); weight[ivec]=1.0; wdf[ivec]=1.0; - if( v>epsilon ){ weight[ivec] = 1.0 / v; wdf[ivec] = 1.0 / ( v*v*v ); } + for(unsigned ivec=0; ivec<nvectors; ++ivec) { + double v=0; for(unsigned jcomp=0; jcomp<3; ++jcomp) v += myvals.get( 2+3*ivec+jcomp )*myvals.get( 2+3*ivec+jcomp ); + v=sqrt(v); weight[ivec]=1.0; wdf[ivec]=1.0; + if( v>epsilon ) { weight[ivec] = 1.0 / v; wdf[ivec] = 1.0 / ( v*v*v ); } } - for(unsigned j=0;j<myvals.getNumberActive();++j){ - unsigned jder=myvals.getActiveIndex(j); - for(unsigned ivec=0;ivec<nvectors;++ivec){ - double comp2=0.0; for(unsigned jcomp=0;jcomp<3;++jcomp) comp2 += myvals.get(2+3*ivec+jcomp)*myvals.getDerivative( 2+3*ivec+jcomp, jder ); - for(unsigned jcomp=0;jcomp<3;++jcomp){ - myvals.setDerivative( 2+3*ivec+jcomp, jder, weight[ivec]*myvals.getDerivative( 2+3*ivec+jcomp, jder ) - wdf[ivec]*comp2*myvals.get(2+3*ivec+jcomp) ); - } + for(unsigned j=0; j<myvals.getNumberActive(); ++j) { + unsigned jder=myvals.getActiveIndex(j); + for(unsigned ivec=0; ivec<nvectors; ++ivec) { + double comp2=0.0; for(unsigned jcomp=0; jcomp<3; ++jcomp) comp2 += myvals.get(2+3*ivec+jcomp)*myvals.getDerivative( 2+3*ivec+jcomp, jder ); + for(unsigned jcomp=0; jcomp<3; ++jcomp) { + myvals.setDerivative( 2+3*ivec+jcomp, jder, weight[ivec]*myvals.getDerivative( 2+3*ivec+jcomp, jder ) - wdf[ivec]*comp2*myvals.get(2+3*ivec+jcomp) ); } - } -} + } + } +} } } diff --git a/src/crystallization/MoleculePlane.cpp b/src/crystallization/MoleculePlane.cpp index 5a503e7c1..9cae7fa51 100644 --- a/src/crystallization/MoleculePlane.cpp +++ b/src/crystallization/MoleculePlane.cpp @@ -47,23 +47,23 @@ public: PLUMED_REGISTER_ACTION(MoleculePlane,"PLANES") -void MoleculePlane::registerKeywords( Keywords& keys ){ +void MoleculePlane::registerKeywords( Keywords& keys ) { VectorMultiColvar::registerKeywords( keys ); keys.use("VMEAN"); keys.add("numbered","MOL","The numerical indices of the atoms in the molecule. If three atoms are specified the orientation " - "of the molecule is taken as the normal to the plane containing the vector connecting the first and " - "second atoms and the vector connecting the second and third atoms. If four atoms are specified the " - "orientation of the molecule is taken as the normal to the plane containing the vector connecting the " - "first and second atoms and the vector connecting the third and fourth atoms. The molecule is always " - "assumed to lie at the geometric centre for the three/four atoms."); + "of the molecule is taken as the normal to the plane containing the vector connecting the first and " + "second atoms and the vector connecting the second and third atoms. If four atoms are specified the " + "orientation of the molecule is taken as the normal to the plane containing the vector connecting the " + "first and second atoms and the vector connecting the third and fourth atoms. The molecule is always " + "assumed to lie at the geometric centre for the three/four atoms."); keys.reset_style("MOL","atoms"); } MoleculePlane::MoleculePlane( const ActionOptions& ao ): -Action(ao), -VectorMultiColvar(ao) + Action(ao), + VectorMultiColvar(ao) { std::vector<AtomNumber> all_atoms; - readAtomsLikeKeyword("MOL",-1,all_atoms); + readAtomsLikeKeyword("MOL",-1,all_atoms); if( ablocks.size()!=3 && ablocks.size()!=4 ) error("number of atoms in molecule specification is wrong. Should be three or four."); if( all_atoms.size()==0 ) error("No atoms were specified"); @@ -76,56 +76,56 @@ AtomNumber MoleculePlane::getAbsoluteIndexOfCentralAtom( const unsigned& iatom ) return ActionAtomistic::getAbsoluteIndex( ablocks[0][atom_lab[iatom].second] ); } -void MoleculePlane::calculateVector( multicolvar::AtomValuePack& myatoms ) const { - Vector d1, d2, cp; - if( myatoms.getNumberOfAtoms()==3 ){ - d1=getSeparation( myatoms.getPosition(1), myatoms.getPosition(0) ); - d2=getSeparation( myatoms.getPosition(1), myatoms.getPosition(2) ); +void MoleculePlane::calculateVector( multicolvar::AtomValuePack& myatoms ) const { + Vector d1, d2, cp; + if( myatoms.getNumberOfAtoms()==3 ) { + d1=getSeparation( myatoms.getPosition(1), myatoms.getPosition(0) ); + d2=getSeparation( myatoms.getPosition(1), myatoms.getPosition(2) ); } else { - d1=getSeparation( myatoms.getPosition(1), myatoms.getPosition(0) ); - d2=getSeparation( myatoms.getPosition(2), myatoms.getPosition(3) ); + d1=getSeparation( myatoms.getPosition(1), myatoms.getPosition(0) ); + d2=getSeparation( myatoms.getPosition(2), myatoms.getPosition(3) ); } cp = crossProduct( d1, d2 ); addAtomDerivatives( 2, 0, crossProduct( Vector(-1.0,0,0), d2 ), myatoms ); - if( myatoms.getNumberOfAtoms()==3 ){ - addAtomDerivatives( 2, 1, crossProduct( Vector(+1.0,0,0), d2 ) + crossProduct( Vector(-1.0,0,0), d1 ), myatoms ); - addAtomDerivatives( 2, 2, crossProduct( Vector(+1.0,0,0), d1 ), myatoms ); + if( myatoms.getNumberOfAtoms()==3 ) { + addAtomDerivatives( 2, 1, crossProduct( Vector(+1.0,0,0), d2 ) + crossProduct( Vector(-1.0,0,0), d1 ), myatoms ); + addAtomDerivatives( 2, 2, crossProduct( Vector(+1.0,0,0), d1 ), myatoms ); } else { - addAtomDerivatives( 2, 1, crossProduct( Vector(+1.0,0,0), d2 ), myatoms ); - addAtomDerivatives( 2, 2, crossProduct( Vector(-1.0,0,0), d1 ), myatoms ); - addAtomDerivatives( 2, 3, crossProduct( Vector(+1.0,0,0), d1 ), myatoms ); + addAtomDerivatives( 2, 1, crossProduct( Vector(+1.0,0,0), d2 ), myatoms ); + addAtomDerivatives( 2, 2, crossProduct( Vector(-1.0,0,0), d1 ), myatoms ); + addAtomDerivatives( 2, 3, crossProduct( Vector(+1.0,0,0), d1 ), myatoms ); } myatoms.addBoxDerivatives( 2, Tensor(d1,crossProduct(Vector(+1.0,0,0), d2)) + Tensor( d2, crossProduct(Vector(-1.0,0,0), d1)) ); myatoms.addValue( 2, cp[0] ); addAtomDerivatives( 3, 0, crossProduct( Vector(0,-1.0,0), d2 ), myatoms ); - if( myatoms.getNumberOfAtoms()==3 ){ - addAtomDerivatives( 3, 1, crossProduct( Vector(0,+1.0,0), d2 ) + crossProduct( Vector(0,-1.0,0), d1 ), myatoms ); - addAtomDerivatives( 3, 2, crossProduct( Vector(0,+1.0,0), d1 ), myatoms ); + if( myatoms.getNumberOfAtoms()==3 ) { + addAtomDerivatives( 3, 1, crossProduct( Vector(0,+1.0,0), d2 ) + crossProduct( Vector(0,-1.0,0), d1 ), myatoms ); + addAtomDerivatives( 3, 2, crossProduct( Vector(0,+1.0,0), d1 ), myatoms ); } else { - addAtomDerivatives( 3, 1, crossProduct( Vector(0,+1.0,0), d2 ), myatoms ); - addAtomDerivatives( 3, 2, crossProduct( Vector(0,-1.0,0), d1 ), myatoms ); - addAtomDerivatives( 3, 3, crossProduct( Vector(0,+1.0,0), d1 ), myatoms ); + addAtomDerivatives( 3, 1, crossProduct( Vector(0,+1.0,0), d2 ), myatoms ); + addAtomDerivatives( 3, 2, crossProduct( Vector(0,-1.0,0), d1 ), myatoms ); + addAtomDerivatives( 3, 3, crossProduct( Vector(0,+1.0,0), d1 ), myatoms ); } myatoms.addBoxDerivatives( 3, Tensor(d1,crossProduct(Vector(0,+1.0,0), d2)) + Tensor( d2, crossProduct(Vector(0,-1.0,0), d1)) ); myatoms.addValue( 3, cp[1] ); addAtomDerivatives( 4, 0, crossProduct( Vector(0,0,-1.0), d2 ), myatoms ); - if( myatoms.getNumberOfAtoms()==3 ){ - addAtomDerivatives( 4, 1, crossProduct( Vector(0,0,+1.0), d2 ) + crossProduct( Vector(0,0,-1.0), d1 ), myatoms ); - addAtomDerivatives( 4, 2, crossProduct( Vector(0,0,+1.0), d1 ), myatoms); + if( myatoms.getNumberOfAtoms()==3 ) { + addAtomDerivatives( 4, 1, crossProduct( Vector(0,0,+1.0), d2 ) + crossProduct( Vector(0,0,-1.0), d1 ), myatoms ); + addAtomDerivatives( 4, 2, crossProduct( Vector(0,0,+1.0), d1 ), myatoms); } else { - addAtomDerivatives( 4, 1, crossProduct( Vector(0,0,-1.0), d2 ), myatoms); - addAtomDerivatives( 4, 2, crossProduct( Vector(0,0,-1.0), d1 ), myatoms); - addAtomDerivatives( 4, 3, crossProduct( Vector(0,0,+1.0), d1 ), myatoms); + addAtomDerivatives( 4, 1, crossProduct( Vector(0,0,-1.0), d2 ), myatoms); + addAtomDerivatives( 4, 2, crossProduct( Vector(0,0,-1.0), d1 ), myatoms); + addAtomDerivatives( 4, 3, crossProduct( Vector(0,0,+1.0), d1 ), myatoms); } myatoms.addBoxDerivatives( 4, Tensor(d1,crossProduct(Vector(0,0,+1.0), d2)) + Tensor( d2, crossProduct(Vector(0,0,-1.0), d1)) ); myatoms.addValue( 4, cp[2] ); } // Vector MoleculePlane::getCentralAtom(){ -// Vector com; com.zero(); +// Vector com; com.zero(); // if( getNAtoms()==3 ){ // com+=(1.0/3.0)*getPosition(0); // com+=(1.0/3.0)*getPosition(1); diff --git a/src/crystallization/OrientationSphere.cpp b/src/crystallization/OrientationSphere.cpp index b17a2821c..8d6fa46d1 100644 --- a/src/crystallization/OrientationSphere.cpp +++ b/src/crystallization/OrientationSphere.cpp @@ -25,40 +25,40 @@ using namespace std; -namespace PLMD{ +namespace PLMD { namespace crystallization { -void OrientationSphere::registerKeywords( Keywords& keys ){ +void OrientationSphere::registerKeywords( Keywords& keys ) { multicolvar::MultiColvarBase::registerKeywords( keys ); keys.add("compulsory","NN","6","The n parameter of the switching function "); keys.add("compulsory","MM","0","The m parameter of the switching function; 0 implies 2*NN"); keys.add("compulsory","D_0","0.0","The d_0 parameter of the switching function"); keys.add("compulsory","R_0","The r_0 parameter of the switching function"); keys.add("optional","SWITCH","This keyword is used if you want to employ an alternative to the continuous swiching function defined above. " - "The following provides information on the \\ref switchingfunction that are available. " - "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); + "The following provides information on the \\ref switchingfunction that are available. " + "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); // Use actionWithDistributionKeywords - keys.use("SPECIES"); keys.use("SPECIESA"); keys.use("SPECIESB"); - keys.use("MEAN"); keys.use("MORE_THAN"); keys.use("LESS_THAN"); + keys.use("SPECIES"); keys.use("SPECIESA"); keys.use("SPECIESB"); + keys.use("MEAN"); keys.use("MORE_THAN"); keys.use("LESS_THAN"); keys.use("MIN"); keys.use("BETWEEN"); keys.use("HISTOGRAM"); keys.use("MOMENTS"); - keys.use("LOWEST"); keys.use("HIGHEST"); + keys.use("LOWEST"); keys.use("HIGHEST"); } OrientationSphere::OrientationSphere(const ActionOptions&ao): -Action(ao), -MultiColvarBase(ao) + Action(ao), + MultiColvarBase(ao) { if( getNumberOfBaseMultiColvars()>1 ) warning("not sure if orientation sphere works with more than one base multicolvar - check numerical derivatives"); // Read in the switching function std::string sw, errors; parse("SWITCH",sw); - if(sw.length()>0){ - switchingFunction.set(sw,errors); - } else { - double r_0=-1.0, d_0; int nn, mm; - parse("NN",nn); parse("MM",mm); - parse("R_0",r_0); parse("D_0",d_0); - if( r_0<0.0 ) error("you must set a value for R_0"); - switchingFunction.set(nn,mm,r_0,d_0); + if(sw.length()>0) { + switchingFunction.set(sw,errors); + } else { + double r_0=-1.0, d_0; int nn, mm; + parse("NN",nn); parse("MM",mm); + parse("R_0",r_0); parse("D_0",d_0); + if( r_0<0.0 ) error("you must set a value for R_0"); + switchingFunction.set(nn,mm,r_0,d_0); } log.printf(" degree of overlap in orientation between central molecule and those within %s\n",( switchingFunction.description() ).c_str() ); log<<" Bibliography "<<plumed.cite("Tribello, Giberti, Sosso, Salvalaglio and Parrinello, J. Chem. Theory Comput. 13, 1317 (2017)")<<"\n"; @@ -69,59 +69,59 @@ MultiColvarBase(ao) } double OrientationSphere::compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ) const { - double d2, sw, value=0, denom=0, dfunc; Vector ddistance; - unsigned ncomponents=getBaseMultiColvar(0)->getNumberOfQuantities(); - std::vector<double> catom_orient( ncomponents ), this_orient( ncomponents ); - std::vector<double> this_der( ncomponents ), catom_der( ncomponents ); - - getInputData( 0, true, myatoms, catom_orient ); - MultiValue& myder0=getInputDerivatives( 0, true, myatoms ); - - for(unsigned i=1;i<myatoms.getNumberOfAtoms();++i){ - Vector& distance=myatoms.getPosition(i); - if ( (d2=distance[0]*distance[0])<rcut2 && - (d2+=distance[1]*distance[1])<rcut2 && - (d2+=distance[2]*distance[2])<rcut2) { - - sw = switchingFunction.calculateSqr( d2, dfunc ); - - getInputData( i, true, myatoms, this_orient ); - // Calculate the dot product wrt to this position - double f_dot = computeVectorFunction( distance, catom_orient, this_orient, ddistance, catom_der, this_der ); - - if( !doNotCalculateDerivatives() ){ - for(unsigned k=2;k<catom_orient.size();++k){ this_der[k]*=sw; catom_der[k]*=sw; } - MultiValue& myder1=getInputDerivatives( i, true, myatoms ); - mergeInputDerivatives( 1, 2, this_orient.size(), 0, catom_der, myder0, myatoms ); - mergeInputDerivatives( 1, 2, catom_der.size(), i, this_der, myder1, myatoms ); - addAtomDerivatives( 1, 0, f_dot*(-dfunc)*distance - sw*ddistance, myatoms ); - addAtomDerivatives( 1, i, f_dot*(dfunc)*distance + sw*ddistance, myatoms ); - myatoms.addBoxDerivatives( 1, (-dfunc)*f_dot*Tensor(distance,distance) - sw*extProduct(distance,ddistance) ); - myder1.clearAll(); - - addAtomDerivatives( -1, 0, (-dfunc)*distance, myatoms ); - addAtomDerivatives( -1, i, (dfunc)*distance, myatoms ); - myatoms.addTemporyBoxDerivatives( (-dfunc)*Tensor(distance,distance) ); - - } - value += sw*f_dot; - denom += sw; + double d2, sw, value=0, denom=0, dfunc; Vector ddistance; + unsigned ncomponents=getBaseMultiColvar(0)->getNumberOfQuantities(); + std::vector<double> catom_orient( ncomponents ), this_orient( ncomponents ); + std::vector<double> this_der( ncomponents ), catom_der( ncomponents ); + + getInputData( 0, true, myatoms, catom_orient ); + MultiValue& myder0=getInputDerivatives( 0, true, myatoms ); + + for(unsigned i=1; i<myatoms.getNumberOfAtoms(); ++i) { + Vector& distance=myatoms.getPosition(i); + if ( (d2=distance[0]*distance[0])<rcut2 && + (d2+=distance[1]*distance[1])<rcut2 && + (d2+=distance[2]*distance[2])<rcut2) { + + sw = switchingFunction.calculateSqr( d2, dfunc ); + + getInputData( i, true, myatoms, this_orient ); + // Calculate the dot product wrt to this position + double f_dot = computeVectorFunction( distance, catom_orient, this_orient, ddistance, catom_der, this_der ); + + if( !doNotCalculateDerivatives() ) { + for(unsigned k=2; k<catom_orient.size(); ++k) { this_der[k]*=sw; catom_der[k]*=sw; } + MultiValue& myder1=getInputDerivatives( i, true, myatoms ); + mergeInputDerivatives( 1, 2, this_orient.size(), 0, catom_der, myder0, myatoms ); + mergeInputDerivatives( 1, 2, catom_der.size(), i, this_der, myder1, myatoms ); + addAtomDerivatives( 1, 0, f_dot*(-dfunc)*distance - sw*ddistance, myatoms ); + addAtomDerivatives( 1, i, f_dot*(dfunc)*distance + sw*ddistance, myatoms ); + myatoms.addBoxDerivatives( 1, (-dfunc)*f_dot*Tensor(distance,distance) - sw*extProduct(distance,ddistance) ); + myder1.clearAll(); + + addAtomDerivatives( -1, 0, (-dfunc)*distance, myatoms ); + addAtomDerivatives( -1, i, (dfunc)*distance, myatoms ); + myatoms.addTemporyBoxDerivatives( (-dfunc)*Tensor(distance,distance) ); + } - } - double rdenom, df2, pref=calculateCoordinationPrefactor( denom, df2 ); - if( fabs(denom)>epsilon ){ rdenom = 1.0 / denom; } - else { plumed_assert(fabs(value)<epsilon); rdenom=1.0; } - - // Now divide everything - double rdenom2=rdenom*rdenom; - updateActiveAtoms( myatoms ); MultiValue& myvals=myatoms.getUnderlyingMultiValue(); - for(unsigned i=0;i<myvals.getNumberActive();++i){ - unsigned ider=myvals.getActiveIndex(i); - double dgd=myvals.getTemporyDerivative(ider); - myvals.setDerivative( 1, ider, rdenom*(pref*myvals.getDerivative(1,ider)+value*df2*dgd) - (value*pref*dgd)*rdenom2 ); - } - - return pref*rdenom*value; + value += sw*f_dot; + denom += sw; + } + } + double rdenom, df2, pref=calculateCoordinationPrefactor( denom, df2 ); + if( fabs(denom)>epsilon ) { rdenom = 1.0 / denom; } + else { plumed_assert(fabs(value)<epsilon); rdenom=1.0; } + + // Now divide everything + double rdenom2=rdenom*rdenom; + updateActiveAtoms( myatoms ); MultiValue& myvals=myatoms.getUnderlyingMultiValue(); + for(unsigned i=0; i<myvals.getNumberActive(); ++i) { + unsigned ider=myvals.getActiveIndex(i); + double dgd=myvals.getTemporyDerivative(ider); + myvals.setDerivative( 1, ider, rdenom*(pref*myvals.getDerivative(1,ider)+value*df2*dgd) - (value*pref*dgd)*rdenom2 ); + } + + return pref*rdenom*value; } } diff --git a/src/crystallization/OrientationSphere.h b/src/crystallization/OrientationSphere.h index 90bf5dbf0..1600d6477 100644 --- a/src/crystallization/OrientationSphere.h +++ b/src/crystallization/OrientationSphere.h @@ -37,10 +37,10 @@ public: static void registerKeywords( Keywords& keys ); explicit OrientationSphere(const ActionOptions&); double compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ) const ; - virtual double computeVectorFunction( const Vector& conn, const std::vector<double>& vec1, const std::vector<double>& vec2, + virtual double computeVectorFunction( const Vector& conn, const std::vector<double>& vec1, const std::vector<double>& vec2, Vector& dconn, std::vector<double>& dvec1, std::vector<double>& dvec2 ) const = 0; virtual double calculateCoordinationPrefactor( const double& coord, double& df ) const ; - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } }; inline diff --git a/src/crystallization/Q3.cpp b/src/crystallization/Q3.cpp index 25a5b77bd..6c3aeedc2 100644 --- a/src/crystallization/Q3.cpp +++ b/src/crystallization/Q3.cpp @@ -20,7 +20,7 @@ along with plumed. If not, see <http://www.gnu.org/licenses/>. +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ #include "Steinhardt.h" -#include "LocalSteinhardt.h" +#include "LocalSteinhardt.h" #include "core/ActionRegister.h" //+PLUMEDOC MCOLVAR Q3 @@ -28,7 +28,7 @@ Calculate 3rd order Steinhardt parameters. The 3rd order Steinhardt parameters allow us to measure the degree to which the first coordination shell -around an atom is ordered. The Steinhardt parameter for atom, \f$i\f$ is complex vector whose components are +around an atom is ordered. The Steinhardt parameter for atom, \f$i\f$ is complex vector whose components are calculated using the following formula: \f[ @@ -36,9 +36,9 @@ q_{3m}(i) = \frac{\sum_j \sigma( r_{ij} ) Y_{3m}(\mathbf{r}_{ij}) }{\sum_j \sigm \f] where \f$Y_{3m}\f$ is one of the 3rd order spherical harmonics so \f$m\f$ is a number that runs from \f$-3\f$ to -\f$+3\f$. The function \f$\sigma( r_{ij} )\f$ is a \ref switchingfunction that acts on the distance between +\f$+3\f$. The function \f$\sigma( r_{ij} )\f$ is a \ref switchingfunction that acts on the distance between atoms \f$i\f$ and \f$j\f$. The parameters of this function should be set so that it the function is equal to one -when atom \f$j\f$ is in the first coordination sphere of atom \f$i\f$ and is zero otherwise. +when atom \f$j\f$ is in the first coordination sphere of atom \f$i\f$ and is zero otherwise. The Steinhardt parameters can be used to measure the degree of order in the system in a variety of different ways. The simplest way of measuring whether or not the coordination sphere is ordered is to simply take the norm of the above vector i.e. @@ -47,11 +47,11 @@ simplest way of measuring whether or not the coordination sphere is ordered is t Q_3(i) = \sqrt{ \sum_{m=-3}^3 q_{3m}(i)^{*} q_{3m}(i) } \f] -This norm is small when the coordination shell is disordered and larger when the coordination shell is ordered. Furthermore, when +This norm is small when the coordination shell is disordered and larger when the coordination shell is ordered. Furthermore, when the keywords LESS_THAN, MIN, MAX, HISTOGRAM, MEAN and so on are used with this colvar it is the distribution of these normed quantities -that is investigated. +that is investigated. -Other measures of order can be taken by averaging the components of the individual \f$q_3\f$ vectors individually or by taking dot products of +Other measures of order can be taken by averaging the components of the individual \f$q_3\f$ vectors individually or by taking dot products of the \f$q_{3}\f$ vectors on adjacent atoms. More information on these variables can be found in the documentation for \ref LOCAL_Q3, \ref LOCAL_AVERAGE and \ref NLINKS. @@ -75,7 +75,7 @@ PRINT ARG=q3.* FILE=colvar The following command could be used to measure the Q3 paramters that describe the arrangement of chlorine ions around the sodium atoms in NaCl. The imagined system here is composed of 64 NaCl formula units and the atoms are arranged in the input -with the 64 Na\f$^+\f$ ions followed by the 64 Cl\f$-\f$ ions. Once again the average Q3 paramter is calculated and output to a +with the 64 Na\f$^+\f$ ions followed by the 64 Cl\f$-\f$ ions. Once again the average Q3 paramter is calculated and output to a file called colvar \verbatim @@ -92,12 +92,12 @@ Calculate the local degree of order around an atoms by taking the average dot pr on the atoms in the first coordination sphere. The \ref Q3 command allows one to calculate one complex vectors for each of the atoms in your system that describe the degree of order in the coordination sphere -around a particular atom. The difficulty with these vectors comes when combining the order parameters from all of the individual atoms/molecules so as to get a -measure of the global degree of order for the system. The simplest way of doing this - calculating the average Steinhardt parameter - can be problematic. If one is +around a particular atom. The difficulty with these vectors comes when combining the order parameters from all of the individual atoms/molecules so as to get a +measure of the global degree of order for the system. The simplest way of doing this - calculating the average Steinhardt parameter - can be problematic. If one is examining nucleation say only the order parameters for those atoms in the nucleus will change significantly when the nucleus forms. The order parameters for the atoms in the surrounding liquid will remain pretty much the same. As such if one models a small nucleus embedded in a very large amount of solution/melt any -change in the average order parameter will be negligible. Substantial changes in the value of this average can be observed in simulations of nucleation but only -because the number of atoms is relatively small. +change in the average order parameter will be negligible. Substantial changes in the value of this average can be observed in simulations of nucleation but only +because the number of atoms is relatively small. When the average \ref Q3 parameter is used to bias the dynamics a problems can occur. These averaged coordinates cannot distinguish between the correct, @@ -116,17 +116,17 @@ biased dynamics what is really required is an order parameter that measures: - Whether or not the atoms that are ordered are clustered together in a crystalline nucleus \ref LOCAL_AVERAGE and \ref NLINKS are variables that can be combined with the Steinhardt parameteters allow to calculate variables that satisfy these requirements. -LOCAL_Q3 is another variable that can be used in these sorts of calculations. The LOCAL_Q3 parameter for a particular atom is a number that measures the extent to -which the orientation of the atoms in the first coordination sphere of an atom match the orientation of the central atom. It does this by calculating the following +LOCAL_Q3 is another variable that can be used in these sorts of calculations. The LOCAL_Q3 parameter for a particular atom is a number that measures the extent to +which the orientation of the atoms in the first coordination sphere of an atom match the orientation of the central atom. It does this by calculating the following quantity for each of the atoms in the system: \f[ s_i = \frac{ \sum_j \sigma( r_{ij} ) \sum_{m=-3}^3 q_{3m}^{*}(i)q_{3m}(j) }{ \sum_j \sigma( r_{ij} ) } \f] - + where \f$q_{3m}(i)\f$ and \f$q_{3m}(j)\f$ are the 3rd order Steinhardt vectors calculated for atom \f$i\f$ and atom \f$j\f$ respectively and the asterix denotes complex conjugation. The function -\f$\sigma( r_{ij} )\f$ is a \ref switchingfunction that acts on the distance between atoms \f$i\f$ and \f$j\f$. The parameters of this function should be set +\f$\sigma( r_{ij} )\f$ is a \ref switchingfunction that acts on the distance between atoms \f$i\f$ and \f$j\f$. The parameters of this function should be set so that it the function is equal to one when atom \f$j\f$ is in the first coordination sphere of atom \f$i\f$ and is zero otherwise. The sum in the numerator of this expression is the dot product of the Steinhardt parameters for atoms \f$i\f$ and \f$j\f$ and thus measures the degree to which the orientations of these adjacent atoms is correlated. @@ -178,13 +178,13 @@ PLUMED_REGISTER_ACTION(Q3,"Q3") typedef LocalSteinhardt<Q3> LOCAL_Q3; PLUMED_REGISTER_ACTION(LOCAL_Q3,"LOCAL_Q3") -void Q3::registerKeywords( Keywords& keys ){ +void Q3::registerKeywords( Keywords& keys ) { Steinhardt::registerKeywords( keys ); } Q3::Q3(const ActionOptions& ao ): -Action(ao), -Steinhardt(ao) + Action(ao), + Steinhardt(ao) { setAngularMomentum(3); @@ -200,10 +200,10 @@ Steinhardt(ao) // Legendre polynomial coefficients of order three - coeff_poly.resize( 4 ); - coeff_poly[0]=0.0; + coeff_poly.resize( 4 ); + coeff_poly[0]=0.0; coeff_poly[1]=-1.5; - coeff_poly[2]=0.0; + coeff_poly[2]=0.0; coeff_poly[3]=2.5; } diff --git a/src/crystallization/Q4.cpp b/src/crystallization/Q4.cpp index 6be9c9b47..fa76b0d10 100644 --- a/src/crystallization/Q4.cpp +++ b/src/crystallization/Q4.cpp @@ -20,7 +20,7 @@ along with plumed. If not, see <http://www.gnu.org/licenses/>. +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ #include "Steinhardt.h" -#include "LocalSteinhardt.h" +#include "LocalSteinhardt.h" #include "core/ActionRegister.h" //+PLUMEDOC MCOLVAR Q4 @@ -28,7 +28,7 @@ Calculate 4th order Steinhardt parameters. The 4th order Steinhardt parameters allow us to measure the degree to which the first coordination shell -around an atom is ordered. The Steinhardt parameter for atom, \f$i\f$ is complex vector whose components are +around an atom is ordered. The Steinhardt parameter for atom, \f$i\f$ is complex vector whose components are calculated using the following formula: \f[ @@ -36,9 +36,9 @@ q_{4m}(i) = \frac{\sum_j \sigma( r_{ij} ) Y_{4m}(\mathbf{r}_{ij}) }{\sum_j \sigm \f] where \f$Y_{4m}\f$ is one of the 4th order spherical harmonics so \f$m\f$ is a number that runs from \f$-4\f$ to -\f$+4\f$. The function \f$\sigma( r_{ij} )\f$ is a \ref switchingfunction that acts on the distance between +\f$+4\f$. The function \f$\sigma( r_{ij} )\f$ is a \ref switchingfunction that acts on the distance between atoms \f$i\f$ and \f$j\f$. The parameters of this function should be set so that it the function is equal to one -when atom \f$j\f$ is in the first coordination sphere of atom \f$i\f$ and is zero otherwise. +when atom \f$j\f$ is in the first coordination sphere of atom \f$i\f$ and is zero otherwise. The Steinhardt parameters can be used to measure the degree of order in the system in a variety of different ways. The simplest way of measuring whether or not the coordination sphere is ordered is to simply take the norm of the above vector i.e. @@ -47,11 +47,11 @@ simplest way of measuring whether or not the coordination sphere is ordered is t Q_4(i) = \sqrt{ \sum_{m=-4}^4 q_{4m}(i)^{*} q_{4m}(i) } \f] -This norm is small when the coordination shell is disordered and larger when the coordination shell is ordered. Furthermore, when +This norm is small when the coordination shell is disordered and larger when the coordination shell is ordered. Furthermore, when the keywords LESS_THAN, MIN, MAX, HISTOGRAM, MEAN and so on are used with this colvar it is the distribution of these normed quantities -that is investigated. +that is investigated. -Other measures of order can be taken by averaging the components of the individual \f$q_4\f$ vectors individually or by taking dot products of +Other measures of order can be taken by averaging the components of the individual \f$q_4\f$ vectors individually or by taking dot products of the \f$q_{4}\f$ vectors on adjacent atoms. More information on these variables can be found in the documentation for \ref LOCAL_Q4, \ref LOCAL_AVERAGE and \ref NLINKS. @@ -75,7 +75,7 @@ PRINT ARG=q4.* FILE=colvar The following command could be used to measure the Q4 paramters that describe the arrangement of chlorine ions around the sodium atoms in NaCl. The imagined system here is composed of 64 NaCl formula units and the atoms are arranged in the input -with the 64 Na\f$^+\f$ ions followed by the 64 Cl\f$-\f$ ions. Once again the average Q4 paramter is calculated and output to a +with the 64 Na\f$^+\f$ ions followed by the 64 Cl\f$-\f$ ions. Once again the average Q4 paramter is calculated and output to a file called colvar \verbatim @@ -92,12 +92,12 @@ Calculate the local degree of order around an atoms by taking the average dot pr on the atoms in the first coordination sphere. The \ref Q4 command allows one to calculate one complex vectors for each of the atoms in your system that describe the degree of order in the coordination sphere -around a particular atom. The difficulty with these vectors comes when combining the order parameters from all of the individual atoms/molecules so as to get a -measure of the global degree of order for the system. The simplest way of doing this - calculating the average Steinhardt parameter - can be problematic. If one is +around a particular atom. The difficulty with these vectors comes when combining the order parameters from all of the individual atoms/molecules so as to get a +measure of the global degree of order for the system. The simplest way of doing this - calculating the average Steinhardt parameter - can be problematic. If one is examining nucleation say only the order parameters for those atoms in the nucleus will change significantly when the nucleus forms. The order parameters for the atoms in the surrounding liquid will remain pretty much the same. As such if one models a small nucleus embedded in a very large amount of solution/melt any -change in the average order parameter will be negligible. Substantial changes in the value of this average can be observed in simulations of nucleation but only -because the number of atoms is relatively small. +change in the average order parameter will be negligible. Substantial changes in the value of this average can be observed in simulations of nucleation but only +because the number of atoms is relatively small. When the average \ref Q4 parameter is used to bias the dynamics a problems can occur. These averaged coordinates cannot distinguish between the correct, @@ -116,17 +116,17 @@ biased dynamics what is really required is an order parameter that measures: - Whether or not the atoms that are ordered are clustered together in a crystalline nucleus \ref LOCAL_AVERAGE and \ref NLINKS are variables that can be combined with the Steinhardt parameteters allow to calculate variables that satisfy these requirements. -LOCAL_Q4 is another variable that can be used in these sorts of calculations. The LOCAL_Q4 parameter for a particular atom is a number that measures the extent to -which the orientation of the atoms in the first coordination sphere of an atom match the orientation of the central atom. It does this by calculating the following +LOCAL_Q4 is another variable that can be used in these sorts of calculations. The LOCAL_Q4 parameter for a particular atom is a number that measures the extent to +which the orientation of the atoms in the first coordination sphere of an atom match the orientation of the central atom. It does this by calculating the following quantity for each of the atoms in the system: \f[ s_i = \frac{ \sum_j \sigma( r_{ij} ) \sum_{m=-4}^4 q_{4m}^{*}(i)q_{4m}(j) }{ \sum_j \sigma( r_{ij} ) } \f] - + where \f$q_{4m}(i)\f$ and \f$q_{4m}(j)\f$ are the 4th order Steinhardt vectors calculated for atom \f$i\f$ and atom \f$j\f$ respectively and the asterix denotes complex conjugation. The function -\f$\sigma( r_{ij} )\f$ is a \ref switchingfunction that acts on the distance between atoms \f$i\f$ and \f$j\f$. The parameters of this function should be set +\f$\sigma( r_{ij} )\f$ is a \ref switchingfunction that acts on the distance between atoms \f$i\f$ and \f$j\f$. The parameters of this function should be set so that it the function is equal to one when atom \f$j\f$ is in the first coordination sphere of atom \f$i\f$ and is zero otherwise. The sum in the numerator of this expression is the dot product of the Steinhardt parameters for atoms \f$i\f$ and \f$j\f$ and thus measures the degree to which the orientations of these adjacent atoms is correlated. @@ -177,13 +177,13 @@ PLUMED_REGISTER_ACTION(Q4,"Q4") typedef LocalSteinhardt<Q4> LOCAL_Q4; PLUMED_REGISTER_ACTION(LOCAL_Q4,"LOCAL_Q4") -void Q4::registerKeywords( Keywords& keys ){ +void Q4::registerKeywords( Keywords& keys ) { Steinhardt::registerKeywords( keys ); } Q4::Q4(const ActionOptions& ao ): -Action(ao), -Steinhardt(ao) + Action(ao), + Steinhardt(ao) { setAngularMomentum(4); @@ -194,10 +194,10 @@ Steinhardt(ao) normaliz[3] = -sqrt( ( 9.0*1) / (4.0*pi*5040.0) ); normaliz[4] = sqrt( (9.0*1) / (4.0*pi*40320.0) ); - coeff_poly.resize( 5 ); + coeff_poly.resize( 5 ); coeff_poly[0]=0.375; coeff_poly[1]=0.0; coeff_poly[2]=-3.75; coeff_poly[3]=0.0; - coeff_poly[4]=4.375; + coeff_poly[4]=4.375; } } diff --git a/src/crystallization/Q6.cpp b/src/crystallization/Q6.cpp index e473d8b65..447b0e1cb 100644 --- a/src/crystallization/Q6.cpp +++ b/src/crystallization/Q6.cpp @@ -28,7 +28,7 @@ Calculate 6th order Steinhardt parameters. The 6th order Steinhardt parameters allow us to measure the degree to which the first coordination shell -around an atom is ordered. The Steinhardt parameter for atom, \f$i\f$ is complex vector whose components are +around an atom is ordered. The Steinhardt parameter for atom, \f$i\f$ is complex vector whose components are calculated using the following formula: \f[ @@ -36,9 +36,9 @@ q_{6m}(i) = \frac{\sum_j \sigma( r_{ij} ) Y_{6m}(\mathbf{r}_{ij}) }{\sum_j \sigm \f] where \f$Y_{6m}\f$ is one of the 6th order spherical harmonics so \f$m\f$ is a number that runs from \f$-6\f$ to -\f$+6\f$. The function \f$\sigma( r_{ij} )\f$ is a \ref switchingfunction that acts on the distance between +\f$+6\f$. The function \f$\sigma( r_{ij} )\f$ is a \ref switchingfunction that acts on the distance between atoms \f$i\f$ and \f$j\f$. The parameters of this function should be set so that it the function is equal to one -when atom \f$j\f$ is in the first coordination sphere of atom \f$i\f$ and is zero otherwise. +when atom \f$j\f$ is in the first coordination sphere of atom \f$i\f$ and is zero otherwise. The Steinhardt parameters can be used to measure the degree of order in the system in a variety of different ways. The simplest way of measuring whether or not the coordination sphere is ordered is to simply take the norm of the above vector i.e. @@ -47,11 +47,11 @@ simplest way of measuring whether or not the coordination sphere is ordered is t Q_6(i) = \sqrt{ \sum_{m=-6}^6 q_{6m}(i)^{*} q_{6m}(i) } \f] -This norm is small when the coordination shell is disordered and larger when the coordination shell is ordered. Furthermore, when +This norm is small when the coordination shell is disordered and larger when the coordination shell is ordered. Furthermore, when the keywords LESS_THAN, MIN, MAX, HISTOGRAM, MEAN and so on are used with this colvar it is the distribution of these normed quantities -that is investigated. +that is investigated. -Other measures of order can be taken by averaging the components of the individual \f$q_6\f$ vectors individually or by taking dot products of +Other measures of order can be taken by averaging the components of the individual \f$q_6\f$ vectors individually or by taking dot products of the \f$q_{6}\f$ vectors on adjacent atoms. More information on these variables can be found in the documentation for \ref LOCAL_Q6, \ref LOCAL_AVERAGE and \ref NLINKS. @@ -75,7 +75,7 @@ PRINT ARG=q6.* FILE=colvar The following command could be used to measure the Q6 paramters that describe the arrangement of chlorine ions around the sodium atoms in NaCl. The imagined system here is composed of 64 NaCl formula units and the atoms are arranged in the input -with the 64 Na\f$^+\f$ ions followed by the 64 Cl\f$-\f$ ions. Once again the average Q6 paramter is calculated and output to a +with the 64 Na\f$^+\f$ ions followed by the 64 Cl\f$-\f$ ions. Once again the average Q6 paramter is calculated and output to a file called colvar \verbatim @@ -92,12 +92,12 @@ Calculate the local degree of order around an atoms by taking the average dot pr on the atoms in the first coordination sphere. The \ref Q6 command allows one to calculate one complex vectors for each of the atoms in your system that describe the degree of order in the coordination sphere -around a particular atom. The difficulty with these vectors comes when combining the order parameters from all of the individual atoms/molecules so as to get a -measure of the global degree of order for the system. The simplest way of doing this - calculating the average Steinhardt parameter - can be problematic. If one is +around a particular atom. The difficulty with these vectors comes when combining the order parameters from all of the individual atoms/molecules so as to get a +measure of the global degree of order for the system. The simplest way of doing this - calculating the average Steinhardt parameter - can be problematic. If one is examining nucleation say only the order parameters for those atoms in the nucleus will change significantly when the nucleus forms. The order parameters for the atoms in the surrounding liquid will remain pretty much the same. As such if one models a small nucleus embedded in a very large amount of solution/melt any -change in the average order parameter will be negligible. Substantial changes in the value of this average can be observed in simulations of nucleation but only -because the number of atoms is relatively small. +change in the average order parameter will be negligible. Substantial changes in the value of this average can be observed in simulations of nucleation but only +because the number of atoms is relatively small. When the average \ref Q6 parameter is used to bias the dynamics a problems can occur. These averaged coordinates cannot distinguish between the correct, @@ -116,17 +116,17 @@ biased dynamics what is really required is an order parameter that measures: - Whether or not the atoms that are ordered are clustered together in a crystalline nucleus \ref LOCAL_AVERAGE and \ref NLINKS are variables that can be combined with the Steinhardt parameteters allow to calculate variables that satisfy these requirements. -LOCAL_Q6 is another variable that can be used in these sorts of calculations. The LOCAL_Q6 parameter for a particular atom is a number that measures the extent to -which the orientation of the atoms in the first coordination sphere of an atom match the orientation of the central atom. It does this by calculating the following +LOCAL_Q6 is another variable that can be used in these sorts of calculations. The LOCAL_Q6 parameter for a particular atom is a number that measures the extent to +which the orientation of the atoms in the first coordination sphere of an atom match the orientation of the central atom. It does this by calculating the following quantity for each of the atoms in the system: \f[ s_i = \frac{ \sum_j \sigma( r_{ij} ) \sum_{m=-6}^6 q_{6m}^{*}(i)q_{6m}(j) }{ \sum_j \sigma( r_{ij} ) } \f] - -where \f$q_{6m}(i)\f$ and \f$q_{6m}(j)\f$ are the 6th order Steinhardt vectors calculated for atom \f$i\f$ and atom \f$j\f$ respectively and the asterix denotes + +where \f$q_{6m}(i)\f$ and \f$q_{6m}(j)\f$ are the 6th order Steinhardt vectors calculated for atom \f$i\f$ and atom \f$j\f$ respectively and the asterix denotes complex conjugation. The function -\f$\sigma( r_{ij} )\f$ is a \ref switchingfunction that acts on the distance between atoms \f$i\f$ and \f$j\f$. The parameters of this function should be set +\f$\sigma( r_{ij} )\f$ is a \ref switchingfunction that acts on the distance between atoms \f$i\f$ and \f$j\f$. The parameters of this function should be set so that it the function is equal to one when atom \f$j\f$ is in the first coordination sphere of atom \f$i\f$ and is zero otherwise. The sum in the numerator of this expression is the dot product of the Steinhardt parameters for atoms \f$i\f$ and \f$j\f$ and thus measures the degree to which the orientations of these adjacent atoms is correlated. @@ -177,13 +177,13 @@ PLUMED_REGISTER_ACTION(Q6,"Q6") typedef LocalSteinhardt<Q6> LOCAL_Q6; PLUMED_REGISTER_ACTION(LOCAL_Q6,"LOCAL_Q6") -void Q6::registerKeywords( Keywords& keys ){ +void Q6::registerKeywords( Keywords& keys ) { Steinhardt::registerKeywords( keys ); } Q6::Q6(const ActionOptions& ao ): -Action(ao), -Steinhardt(ao) + Action(ao), + Steinhardt(ao) { setAngularMomentum(6); @@ -196,11 +196,11 @@ Steinhardt(ao) normaliz[5] = -sqrt( (13.0*1) / (4.0*pi*39916800) ); normaliz[6] = sqrt( (13.0*1) / (4.0*pi*479001600) ); - coeff_poly.resize( 7 ); + coeff_poly.resize( 7 ); coeff_poly[0]=-0.3125; coeff_poly[1]=0.0; coeff_poly[2]=6.5625; coeff_poly[3]=0.0; coeff_poly[4]=-19.6875; coeff_poly[5]=0.0; - coeff_poly[6]=14.4375; + coeff_poly[6]=14.4375; } } diff --git a/src/crystallization/SMAC.cpp b/src/crystallization/SMAC.cpp index 18e9a2ab0..ce83df738 100644 --- a/src/crystallization/SMAC.cpp +++ b/src/crystallization/SMAC.cpp @@ -28,40 +28,40 @@ /* Calculate a variant on the SMAC collective variable discussed in \cite smac-paper -The SMAC collective variable can be used to study the formation of molecular solids -from either the melt or from solution. The idea behind this variable is that what -differentiates a molecular solid from a molecular liquid is an alignment of -internal vectors in neighboring molecules. In other words, the relative orientation +The SMAC collective variable can be used to study the formation of molecular solids +from either the melt or from solution. The idea behind this variable is that what +differentiates a molecular solid from a molecular liquid is an alignment of +internal vectors in neighboring molecules. In other words, the relative orientation of neighboring molecules is no longer random as it is in a liquid. In a solid particular torsional angles between molecules are preferred. As such this CV calculates the following average: \f[ s_i = \frac{ \left\{ 1 - \psi\left[ \sum_{j \ne i} \sigma(r_{ij}) \right] \right\} \sum_{j \ne i} \sigma(r_{ij}) \sum_n K_n(\theta_{ij}) }{ \sum_{j \ne i} \sigma(r_{ij}) } -\f] +\f] In this expression \f$r_{ij}\f$ is the distance between molecule \f$i\f$ and molecule \f$j\f$ and \f$\sigma(r_{ij})\f$ is a \ref switchingfunction that acts on this distance. By including this switching function in the second summation in the -numerator and in the denominator we are thus ensuring that we calculate an average over the molecules in the first coordination -sphere of molecule \f$i\f$. All molecules in higher coordination sphere will essentially contribute zero to the sums in the -above expression because their \f$\sigma(r_{ij})\f$ will be very small. \f$\psi\f$ is also a switching function. The term +numerator and in the denominator we are thus ensuring that we calculate an average over the molecules in the first coordination +sphere of molecule \f$i\f$. All molecules in higher coordination sphere will essentially contribute zero to the sums in the +above expression because their \f$\sigma(r_{ij})\f$ will be very small. \f$\psi\f$ is also a switching function. The term including \f$\psi\f$ in the numerator is there to ensure that only those molecules that are attached to a reasonably large number of molecules. It is important to include this "more than" switching function when you are simulating nucleation -from solution with this CV. Lastly, the $K_n functions are \ref kernelfunctions that take the torsion angle, \f$\theta_{ij}\f$, between the +from solution with this CV. Lastly, the $K_n functions are \ref kernelfunctions that take the torsion angle, \f$\theta_{ij}\f$, between the internal orientation vectors for molecules \f$i\f$ and \f$j\f$ as input. These kernel functions should be set so that they are equal to one when the relative orientation of the moleclues are as they are in the solid and equal to zero otherwise. The final \f$s_i\f$ quantity thus measures whether (on average) the molecules in the first coordination sphere around molecule \f$i\f$ -are oriented as they would be in the solid. Furthermore, this Action is a multicolvar so you can calculate the \f$s_i\f$ values -for all the molecules in your system simultaneously and then determine the average, the number less than and so on. +are oriented as they would be in the solid. Furthermore, this Action is a multicolvar so you can calculate the \f$s_i\f$ values +for all the molecules in your system simultaneously and then determine the average, the number less than and so on. \par Examples -In the example below the orientation of the molecules in the system is determined by calculating the +In the example below the orientation of the molecules in the system is determined by calculating the vector that connects a pair of atoms. SMAC is then used to determine whether the molecules are sitting -in a solid or liquid like environment. We can determine whether the environment is solid or liquid like because in the solid the torsional angle between +in a solid or liquid like environment. We can determine whether the environment is solid or liquid like because in the solid the torsional angle between the bond vectors on adjacent molecules is close to 0 or \f$\pi\f$. The final quantity that is output to the colvar file measures the number of molecules that have a SMAC parameter that is greater than 0.7. N.B. By using -the indices of three atoms for each of the MOL keywords below we are telling PLUMED to use the first two +the indices of three atoms for each of the MOL keywords below we are telling PLUMED to use the first two numbers to determine the orientation of the molecule that will ultimately be used when calculating the \f$\theta_{ij}\f$ terms in the formula above. The atom with the third index meanwhile is used when we calculate \f$r_{ij}\f$. @@ -79,8 +79,8 @@ LABEL=m3 ... MOLECULES SMAC ... - SPECIES=m3 LOWMEM - KERNEL1={GAUSSIAN CENTER=0 SIGMA=0.480} KERNEL2={GAUSSIAN CENTER=pi SIGMA=0.480} + SPECIES=m3 LOWMEM + KERNEL1={GAUSSIAN CENTER=0 SIGMA=0.480} KERNEL2={GAUSSIAN CENTER=pi SIGMA=0.480} SWITCH={RATIONAL R_0=0.6} MORE_THAN={RATIONAL R_0=0.7} SWITCH_COORD={EXP R_0=4} LABEL=s2 ... SMAC @@ -89,7 +89,7 @@ PRINT ARG=s2.* FILE=colvar \endverbatim This second example works in a way that is very similar to the previous command. Now, however, -the orientation of the molecules is determined by finding the plane that contains the positions +the orientation of the molecules is determined by finding the plane that contains the positions of three atoms. \verbatim @@ -106,9 +106,9 @@ VMEAN LABEL=m3 ... PLANES -SMAC ... - SPECIES=m3 LOWMEM - KERNEL1={GAUSSIAN CENTER=0 SIGMA=0.480} KERNEL2={GAUSSIAN CENTER=pi SIGMA=0.480} +SMAC ... + SPECIES=m3 LOWMEM + KERNEL1={GAUSSIAN CENTER=0 SIGMA=0.480} KERNEL2={GAUSSIAN CENTER=pi SIGMA=0.480} SWITCH={RATIONAL R_0=0.6} MORE_THAN={RATIONAL R_0=0.7} SWITCH_COORD={EXP R_0=3.0} LABEL=s2 ... SMAC @@ -127,70 +127,70 @@ private: std::vector<KernelFunctions> kernels; SwitchingFunction coord_switch; public: - static void registerKeywords( Keywords& keys ); - explicit SMAC(const ActionOptions& ao); - double computeVectorFunction( const Vector& conn, const std::vector<double>& vec1, const std::vector<double>& vec2, + static void registerKeywords( Keywords& keys ); + explicit SMAC(const ActionOptions& ao); + double computeVectorFunction( const Vector& conn, const std::vector<double>& vec1, const std::vector<double>& vec2, Vector& dconn, std::vector<double>& dvec1, std::vector<double>& dvec2 ) const ; double calculateCoordinationPrefactor( const double& coord, double& df ) const ; }; PLUMED_REGISTER_ACTION(SMAC,"SMAC") -void SMAC::registerKeywords( Keywords& keys ){ +void SMAC::registerKeywords( Keywords& keys ) { OrientationSphere::registerKeywords(keys); keys.add("numbered","KERNEL","The kernels used in the function of the angle"); keys.add("compulsory","SWITCH_COORD","This keyword is used to define the coordination switching function."); - keys.reset_style("KERNEL","compulsory"); + keys.reset_style("KERNEL","compulsory"); } SMAC::SMAC(const ActionOptions& ao): -Action(ao), -OrientationSphere(ao) + Action(ao), + OrientationSphere(ao) { - if( mybasemulticolvars.size()==0 ) error("SMAC must take multicolvar as input"); - for(unsigned i=0;i<mybasemulticolvars.size();++i){ - if( (mybasemulticolvars[i]->getNumberOfQuantities()-2)%3!=0 ) error("SMAC is only possible with three dimensional vectors"); - } - - std::string kernelinpt; - for(int i=1;;i++){ - if( !parseNumbered("KERNEL",i,kernelinpt) ) break; - KernelFunctions mykernel( kernelinpt, false ); - kernels.push_back( mykernel ); - } - if( kernels.size()==0 ) error("no kernels defined"); - - std::string sw, errors; parse("SWITCH_COORD",sw); - if(sw.length()==0) error("SWITCH_COORD keyword is missing"); - coord_switch.set(sw,errors); - if(errors.length()>0) error("the following errors were found in input to SWITCH_COORD : " + errors ); + if( mybasemulticolvars.size()==0 ) error("SMAC must take multicolvar as input"); + for(unsigned i=0; i<mybasemulticolvars.size(); ++i) { + if( (mybasemulticolvars[i]->getNumberOfQuantities()-2)%3!=0 ) error("SMAC is only possible with three dimensional vectors"); + } + + std::string kernelinpt; + for(int i=1;; i++) { + if( !parseNumbered("KERNEL",i,kernelinpt) ) break; + KernelFunctions mykernel( kernelinpt, false ); + kernels.push_back( mykernel ); + } + if( kernels.size()==0 ) error("no kernels defined"); + + std::string sw, errors; parse("SWITCH_COORD",sw); + if(sw.length()==0) error("SWITCH_COORD keyword is missing"); + coord_switch.set(sw,errors); + if(errors.length()>0) error("the following errors were found in input to SWITCH_COORD : " + errors ); } -double SMAC::computeVectorFunction( const Vector& conn, const std::vector<double>& vec1, const std::vector<double>& vec2, +double SMAC::computeVectorFunction( const Vector& conn, const std::vector<double>& vec1, const std::vector<double>& vec2, Vector& dconn, std::vector<double>& dvec1, std::vector<double>& dvec2 ) const { unsigned nvectors = ( vec1.size() - 2 ) / 3; plumed_assert( (vec1.size()-2)%3==0 ); std::vector<Vector> dv1(nvectors), dv2(nvectors), tdconn(nvectors); Torsion t; std::vector<Vector> v1(nvectors), v2(nvectors); - std::vector<Value*> pos; for(unsigned i=0;i<nvectors;++i){ pos.push_back( new Value() ); pos[i]->setDomain( "-pi", "pi" ); } - - for(unsigned j=0;j<nvectors;++j){ - for(unsigned k=0;k<3;++k){ - v1[j][k]=vec1[2+3*j+k]; v2[j][k]=vec2[2+3*j+k]; - } - double angle = t.compute( v1[j], conn, v2[j], dv1[j], tdconn[j], dv2[j] ); - pos[j]->set( angle ); + std::vector<Value*> pos; for(unsigned i=0; i<nvectors; ++i) { pos.push_back( new Value() ); pos[i]->setDomain( "-pi", "pi" ); } + + for(unsigned j=0; j<nvectors; ++j) { + for(unsigned k=0; k<3; ++k) { + v1[j][k]=vec1[2+3*j+k]; v2[j][k]=vec2[2+3*j+k]; + } + double angle = t.compute( v1[j], conn, v2[j], dv1[j], tdconn[j], dv2[j] ); + pos[j]->set( angle ); } - double ans=0; std::vector<double> deriv( nvectors ), df( nvectors, 0 ); - for(unsigned i=0;i<kernels.size();++i){ - ans += kernels[i].evaluate( pos, deriv ); - for(unsigned j=0;j<nvectors;++j) df[j] += deriv[j]; + double ans=0; std::vector<double> deriv( nvectors ), df( nvectors, 0 ); + for(unsigned i=0; i<kernels.size(); ++i) { + ans += kernels[i].evaluate( pos, deriv ); + for(unsigned j=0; j<nvectors; ++j) df[j] += deriv[j]; } - dconn.zero(); for(unsigned j=0;j<nvectors;++j) dconn += df[j]*tdconn[j]; - for(unsigned j=0;j<nvectors;++j){ - for(unsigned k=0;k<3;++k){ dvec1[2+3*j+k]=df[j]*dv1[j][k]; dvec2[2+3*j+k]=df[j]*dv2[j][k]; } - delete pos[j]; + dconn.zero(); for(unsigned j=0; j<nvectors; ++j) dconn += df[j]*tdconn[j]; + for(unsigned j=0; j<nvectors; ++j) { + for(unsigned k=0; k<3; ++k) { dvec1[2+3*j+k]=df[j]*dv1[j][k]; dvec2[2+3*j+k]=df[j]*dv2[j][k]; } + delete pos[j]; } return ans; } diff --git a/src/crystallization/SimpleCubic.cpp b/src/crystallization/SimpleCubic.cpp index 26a6730ab..4d50cc7d5 100644 --- a/src/crystallization/SimpleCubic.cpp +++ b/src/crystallization/SimpleCubic.cpp @@ -27,8 +27,8 @@ using namespace std; -namespace PLMD{ -namespace crystallization{ +namespace PLMD { +namespace crystallization { //+PLUMEDOC MCOLVAR SIMPLECUBIC /* @@ -42,12 +42,12 @@ the following quantity: s_i = \frac{ \sum_{i \ne j} \sigma(r_{ij}) \left[ \frac{ x_{ij}^4 + y_{ij}^4 + z_{ij}^4 }{r_{ij}^4} \right] }{ \sum_{i \ne j} \sigma(r_{ij}) } \f] -In this expression \f$x_{ij}\f$, \f$y_{ij}\f$ and \f$z_{ij}\f$ are the \f$x\f$, \f$y\f$ and \f$z\f$ components of the vector connecting atom \f$i\f$ to +In this expression \f$x_{ij}\f$, \f$y_{ij}\f$ and \f$z_{ij}\f$ are the \f$x\f$, \f$y\f$ and \f$z\f$ components of the vector connecting atom \f$i\f$ to atom \f$j\f$ and \f$r_{ij}\f$ is the magnitude of this vector. \f$\sigma(r_{ij})\f$ is a \ref switchingfunction that acts on the distance between atom \f$i\f$ and atom \f$j\f$ and its inclusion in the numerator and the denominator of the above expression as well as the fact that we are summing over all of the other atoms in the system ensures that we are calculating an average of the function of \f$x_{ij}\f$, \f$y_{ij}\f$ and \f$z_{ij}\f$ for the atoms in the first coordination sphere around atom \f$i\f$. This quantity is once again a multicolvar so you can compute it for multiple atoms using a single PLUMED action and then compute -the average value for the atoms in your system, the number of atoms that have an \f$s_i\f$ value that is more that some target and +the average value for the atoms in your system, the number of atoms that have an \f$s_i\f$ value that is more that some target and so on. Notice also that you can rotate the reference frame if you are using a non-standard unit cell. @@ -78,38 +78,38 @@ public: PLUMED_REGISTER_ACTION(SimpleCubic,"SIMPLECUBIC") -void SimpleCubic::registerKeywords( Keywords& keys ){ +void SimpleCubic::registerKeywords( Keywords& keys ) { CubicHarmonicBase::registerKeywords( keys ); } SimpleCubic::SimpleCubic(const ActionOptions&ao): -Action(ao), -CubicHarmonicBase(ao) + Action(ao), + CubicHarmonicBase(ao) { checkRead(); } -double SimpleCubic::calculateCubicHarmonic( const Vector& distance, const double& d2, Vector& myder ) const { +double SimpleCubic::calculateCubicHarmonic( const Vector& distance, const double& d2, Vector& myder ) const { double x2 = distance[0]*distance[0]; double x3 = distance[0]*x2; double x4 = distance[0]*x3; double y2 = distance[1]*distance[1]; double y3 = distance[1]*y2; - double y4 = distance[1]*y3; - + double y4 = distance[1]*y3; + double z2 = distance[2]*distance[2]; - double z3 = distance[2]*z2; + double z3 = distance[2]*z2; double z4 = distance[2]*z3; double r4 = pow( d2, 2 ); double tmp = ( x4 + y4 + z4 ) / r4; double t1=(x2+y2+z2), t2=t1*t1, t3=(x4+y4+z4)/(t1*t2); - myder[0] = 4*x3/t2-4*distance[0]*t3; - myder[1] = 4*y3/t2-4*distance[1]*t3; - myder[2] = 4*z3/t2-4*distance[2]*t3; - return tmp; + myder[0] = 4*x3/t2-4*distance[0]*t3; + myder[1] = 4*y3/t2-4*distance[1]*t3; + myder[2] = 4*z3/t2-4*distance[2]*t3; + return tmp; } } diff --git a/src/crystallization/Steinhardt.cpp b/src/crystallization/Steinhardt.cpp index c92653a3b..0cfeb4475 100644 --- a/src/crystallization/Steinhardt.cpp +++ b/src/crystallization/Steinhardt.cpp @@ -26,15 +26,15 @@ namespace PLMD { namespace crystallization { -void Steinhardt::registerKeywords( Keywords& keys ){ - VectorMultiColvar::registerKeywords( keys ); +void Steinhardt::registerKeywords( Keywords& keys ) { + VectorMultiColvar::registerKeywords( keys ); keys.add("compulsory","NN","12","The n parameter of the switching function "); keys.add("compulsory","MM","0","The m parameter of the switching function; 0 implies 2*NN"); keys.add("compulsory","D_0","0.0","The d_0 parameter of the switching function"); keys.add("compulsory","R_0","The r_0 parameter of the switching function"); keys.add("optional","SWITCH","This keyword is used if you want to employ an alternative to the continuous swiching function defined above. " - "The following provides information on the \\ref switchingfunction that are available. " - "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); + "The following provides information on the \\ref switchingfunction that are available. " + "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); keys.use("SPECIES"); keys.use("SPECIESA"); keys.use("SPECIESB"); keys.use("MEAN"); keys.use("LESS_THAN"); keys.use("MORE_THAN"); keys.use("VMEAN"); keys.use("BETWEEN"); keys.use("HISTOGRAM"); keys.use("MOMENTS"); keys.use("MIN"); keys.use("ALT_MIN"); @@ -42,20 +42,20 @@ void Steinhardt::registerKeywords( Keywords& keys ){ } Steinhardt::Steinhardt( const ActionOptions& ao ): -Action(ao), -VectorMultiColvar(ao), -tmom(0) + Action(ao), + VectorMultiColvar(ao), + tmom(0) { // Read in the switching function std::string sw, errors; parse("SWITCH",sw); - if(sw.length()>0){ - switchingFunction.set(sw,errors); + if(sw.length()>0) { + switchingFunction.set(sw,errors); } else { - double r_0=-1.0, d_0; int nn, mm; - parse("NN",nn); parse("MM",mm); - parse("R_0",r_0); parse("D_0",d_0); - if( r_0<0.0 ) error("you must set a value for R_0"); - switchingFunction.set(nn,mm,r_0,d_0); + double r_0=-1.0, d_0; int nn, mm; + parse("NN",nn); parse("MM",mm); + parse("R_0",r_0); parse("D_0",d_0); + if( r_0<0.0 ) error("you must set a value for R_0"); + switchingFunction.set(nn,mm,r_0,d_0); } log.printf(" Steinhardt parameter of central atom and those within %s\n",( switchingFunction.description() ).c_str() ); log<<" Bibliography "<<plumed.cite("Tribello, Giberti, Sosso, Salvalaglio and Parrinello, J. Chem. Theory Comput. 13, 1317 (2017)")<<"\n"; @@ -65,98 +65,98 @@ tmom(0) std::vector<AtomNumber> all_atoms; setupMultiColvarBase( all_atoms ); } -void Steinhardt::setAngularMomentum( const unsigned& ang ){ +void Steinhardt::setAngularMomentum( const unsigned& ang ) { tmom=ang; setVectorDimensionality( 2*(2*ang + 1) ); -} +} void Steinhardt::calculateVector( multicolvar::AtomValuePack& myatoms ) const { - double dfunc, dpoly_ass, md, tq6, itq6, real_z, imag_z; + double dfunc, dpoly_ass, md, tq6, itq6, real_z, imag_z; Vector dz, myrealvec, myimagvec, real_dz, imag_dz; // The square root of -1 std::complex<double> ii( 0.0, 1.0 ), dp_x, dp_y, dp_z; - unsigned ncomp=2*tmom+1; + unsigned ncomp=2*tmom+1; double sw, poly_ass, d2, dlen; std::complex<double> powered; - for(unsigned i=1;i<myatoms.getNumberOfAtoms();++i){ - Vector& distance=myatoms.getPosition(i); // getSeparation( myatoms.getPosition(0), myatoms.getPosition(i) ); - if ( (d2=distance[0]*distance[0])<rcut2 && - (d2+=distance[1]*distance[1])<rcut2 && - (d2+=distance[2]*distance[2])<rcut2) { - dlen = sqrt(d2); - sw = switchingFunction.calculate( dlen, dfunc ); - accumulateSymmetryFunction( -1, i, sw, (+dfunc)*distance, (-dfunc)*Tensor( distance,distance ), myatoms ); - double dlen3 = d2*dlen; - // Do stuff for m=0 - poly_ass=deriv_poly( 0, distance[2]/dlen, dpoly_ass ); - // Derivatives of z/r wrt x, y, z - dz = -( distance[2] / dlen3 )*distance; dz[2] += (1.0 / dlen); - // Derivative wrt to the vector connecting the two atoms - myrealvec = (+sw)*dpoly_ass*dz + poly_ass*(+dfunc)*distance; - // Accumulate the derivatives - accumulateSymmetryFunction( 2 + tmom, i, sw*poly_ass, myrealvec, Tensor( -myrealvec,distance ), myatoms ); - - // The complex number of which we have to take powers - std::complex<double> com1( distance[0]/dlen ,distance[1]/dlen ); - - // Do stuff for all other m values - for(unsigned m=1;m<=tmom;++m){ - // Calculate Legendre Polynomial - poly_ass=deriv_poly( m, distance[2]/dlen, dpoly_ass ); - // Calculate powe of complex number - powered=pow(com1,m-1); md=static_cast<double>(m); - // Real and imaginary parts of z - real_z = real(com1*powered); imag_z = imag(com1*powered ); - - // Calculate steinhardt parameter - tq6=poly_ass*real_z; // Real part of steinhardt parameter - itq6=poly_ass*imag_z; // Imaginary part of steinhardt parameter - - // Derivatives wrt ( x/r + iy )^m - dp_x = md*powered*( (1.0/dlen)-(distance[0]*distance[0])/dlen3-ii*(distance[0]*distance[1])/dlen3 ); - dp_y = md*powered*( ii*(1.0/dlen)-(distance[0]*distance[1])/dlen3-ii*(distance[1]*distance[1])/dlen3 ); - dp_z = md*powered*( -(distance[0]*distance[2])/dlen3-ii*(distance[1]*distance[2])/dlen3 ); - - // Derivatives of real and imaginary parts of above - real_dz[0] = real( dp_x ); real_dz[1] = real( dp_y ); real_dz[2] = real( dp_z ); - imag_dz[0] = imag( dp_x ); imag_dz[1] = imag( dp_y ); imag_dz[2] = imag( dp_z ); - - // Complete derivative of steinhardt parameter - myrealvec = (+sw)*dpoly_ass*real_z*dz + (+dfunc)*distance*tq6 + (+sw)*poly_ass*real_dz; - myimagvec = (+sw)*dpoly_ass*imag_z*dz + (+dfunc)*distance*itq6 + (+sw)*poly_ass*imag_dz; - - // Real part - accumulateSymmetryFunction( 2 + tmom + m, i, sw*tq6, myrealvec, Tensor( -myrealvec,distance ), myatoms ); - // Imaginary part - accumulateSymmetryFunction( 2+ncomp+tmom+m, i, sw*itq6, myimagvec, Tensor( -myimagvec,distance ), myatoms ); - // Store -m part of vector - double pref=pow(-1.0,m); - // -m part of vector is just +m part multiplied by (-1.0)**m and multiplied by complex - // conjugate of Legendre polynomial - // Real part - accumulateSymmetryFunction( 2+tmom-m, i, pref*sw*tq6, pref*myrealvec, pref*Tensor( -myrealvec,distance ), myatoms ); - // Imaginary part - accumulateSymmetryFunction( 2+ncomp+tmom-m, i, -pref*sw*itq6, -pref*myimagvec, pref*Tensor( myimagvec,distance ), myatoms ); - } - } - } - - // Normalize + for(unsigned i=1; i<myatoms.getNumberOfAtoms(); ++i) { + Vector& distance=myatoms.getPosition(i); // getSeparation( myatoms.getPosition(0), myatoms.getPosition(i) ); + if ( (d2=distance[0]*distance[0])<rcut2 && + (d2+=distance[1]*distance[1])<rcut2 && + (d2+=distance[2]*distance[2])<rcut2) { + dlen = sqrt(d2); + sw = switchingFunction.calculate( dlen, dfunc ); + accumulateSymmetryFunction( -1, i, sw, (+dfunc)*distance, (-dfunc)*Tensor( distance,distance ), myatoms ); + double dlen3 = d2*dlen; + // Do stuff for m=0 + poly_ass=deriv_poly( 0, distance[2]/dlen, dpoly_ass ); + // Derivatives of z/r wrt x, y, z + dz = -( distance[2] / dlen3 )*distance; dz[2] += (1.0 / dlen); + // Derivative wrt to the vector connecting the two atoms + myrealvec = (+sw)*dpoly_ass*dz + poly_ass*(+dfunc)*distance; + // Accumulate the derivatives + accumulateSymmetryFunction( 2 + tmom, i, sw*poly_ass, myrealvec, Tensor( -myrealvec,distance ), myatoms ); + + // The complex number of which we have to take powers + std::complex<double> com1( distance[0]/dlen,distance[1]/dlen ); + + // Do stuff for all other m values + for(unsigned m=1; m<=tmom; ++m) { + // Calculate Legendre Polynomial + poly_ass=deriv_poly( m, distance[2]/dlen, dpoly_ass ); + // Calculate powe of complex number + powered=pow(com1,m-1); md=static_cast<double>(m); + // Real and imaginary parts of z + real_z = real(com1*powered); imag_z = imag(com1*powered ); + + // Calculate steinhardt parameter + tq6=poly_ass*real_z; // Real part of steinhardt parameter + itq6=poly_ass*imag_z; // Imaginary part of steinhardt parameter + + // Derivatives wrt ( x/r + iy )^m + dp_x = md*powered*( (1.0/dlen)-(distance[0]*distance[0])/dlen3-ii*(distance[0]*distance[1])/dlen3 ); + dp_y = md*powered*( ii*(1.0/dlen)-(distance[0]*distance[1])/dlen3-ii*(distance[1]*distance[1])/dlen3 ); + dp_z = md*powered*( -(distance[0]*distance[2])/dlen3-ii*(distance[1]*distance[2])/dlen3 ); + + // Derivatives of real and imaginary parts of above + real_dz[0] = real( dp_x ); real_dz[1] = real( dp_y ); real_dz[2] = real( dp_z ); + imag_dz[0] = imag( dp_x ); imag_dz[1] = imag( dp_y ); imag_dz[2] = imag( dp_z ); + + // Complete derivative of steinhardt parameter + myrealvec = (+sw)*dpoly_ass*real_z*dz + (+dfunc)*distance*tq6 + (+sw)*poly_ass*real_dz; + myimagvec = (+sw)*dpoly_ass*imag_z*dz + (+dfunc)*distance*itq6 + (+sw)*poly_ass*imag_dz; + + // Real part + accumulateSymmetryFunction( 2 + tmom + m, i, sw*tq6, myrealvec, Tensor( -myrealvec,distance ), myatoms ); + // Imaginary part + accumulateSymmetryFunction( 2+ncomp+tmom+m, i, sw*itq6, myimagvec, Tensor( -myimagvec,distance ), myatoms ); + // Store -m part of vector + double pref=pow(-1.0,m); + // -m part of vector is just +m part multiplied by (-1.0)**m and multiplied by complex + // conjugate of Legendre polynomial + // Real part + accumulateSymmetryFunction( 2+tmom-m, i, pref*sw*tq6, pref*myrealvec, pref*Tensor( -myrealvec,distance ), myatoms ); + // Imaginary part + accumulateSymmetryFunction( 2+ncomp+tmom-m, i, -pref*sw*itq6, -pref*myimagvec, pref*Tensor( myimagvec,distance ), myatoms ); + } + } + } + + // Normalize updateActiveAtoms( myatoms ); - for(unsigned i=0;i<getNumberOfComponentsInVector();++i) myatoms.getUnderlyingMultiValue().quotientRule( 2+i, 2+i ); + for(unsigned i=0; i<getNumberOfComponentsInVector(); ++i) myatoms.getUnderlyingMultiValue().quotientRule( 2+i, 2+i ); } -double Steinhardt::deriv_poly( const unsigned& m, const double& val, double& df ) const { +double Steinhardt::deriv_poly( const unsigned& m, const double& val, double& df ) const { double fact=1.0; - for(unsigned j=1;j<=m;++j) fact=fact*j; + for(unsigned j=1; j<=m; ++j) fact=fact*j; double res=coeff_poly[m]*fact; double pow=1.0, xi=val, dxi=1.0; df=0.0; - for(int i=m+1;i<=tmom;++i){ - double fact=1.0; - for(unsigned j=i-m+1;j<=i;++j) fact=fact*j; - res=res+coeff_poly[i]*fact*xi; - df = df + pow*coeff_poly[i]*fact*dxi; - xi=xi*val; dxi=dxi*val; pow+=1.0; + for(int i=m+1; i<=tmom; ++i) { + double fact=1.0; + for(unsigned j=i-m+1; j<=i; ++j) fact=fact*j; + res=res+coeff_poly[i]*fact*xi; + df = df + pow*coeff_poly[i]*fact*dxi; + xi=xi*val; dxi=dxi*val; pow+=1.0; } df = df*normaliz[m]; return normaliz[m]*res; diff --git a/src/crystallization/Tetrahedral.cpp b/src/crystallization/Tetrahedral.cpp index d190658fd..616cf766b 100644 --- a/src/crystallization/Tetrahedral.cpp +++ b/src/crystallization/Tetrahedral.cpp @@ -27,25 +27,25 @@ using namespace std; -namespace PLMD{ -namespace crystallization{ +namespace PLMD { +namespace crystallization { //+PLUMEDOC MCOLVAR TETRAHEDRAL /* Calculate the degree to which the environment about ions has a tetrahedral order. -We can measure the degree to which the first coordination shell around any atom, \f$i\f$ is +We can measure the degree to which the first coordination shell around any atom, \f$i\f$ is tetrahedrally ordered using the following function. \f[ - s(i) = \frac{1}{\sum_j \sigma( r_{ij} )} \sum_j \sigma( r_{ij} )\left[ \frac{(x_{ij} + y_{ij} + z_{ij})^3}{r_{ij}^3} + - \frac{(x_{ij} - y_{ij} - z_{ij})^3}{r_{ij}^3} + - \frac{(-x_{ij} + y_{ij} - z_{ij})^3}{r_{ij}^3} + - \frac{(-x_{ij} - y_{ij} + z_{ij})^3}{r_{ij}^3} \right] + s(i) = \frac{1}{\sum_j \sigma( r_{ij} )} \sum_j \sigma( r_{ij} )\left[ \frac{(x_{ij} + y_{ij} + z_{ij})^3}{r_{ij}^3} + + \frac{(x_{ij} - y_{ij} - z_{ij})^3}{r_{ij}^3} + + \frac{(-x_{ij} + y_{ij} - z_{ij})^3}{r_{ij}^3} + + \frac{(-x_{ij} - y_{ij} + z_{ij})^3}{r_{ij}^3} \right] \f] Here \f$r_{ij}\f$ is the magnitude fo the vector connecting atom \f$i\f$ to atom \f$j\f$ and \f$x_{ij}\f$, \f$y_{ij}\f$ and \f$z_{ij}\f$ -are its three components. The function \f$\sigma( r_{ij} )\f$ is a \ref switchingfunction that acts on the distance between +are its three components. The function \f$\sigma( r_{ij} )\f$ is a \ref switchingfunction that acts on the distance between atoms \f$i\f$ and \f$j\f$. The parameters of this function should be set so that the function is equal to one when atom \f$j\f$ is in the first coordination sphere of atom \f$i\f$ and is zero otherwise. @@ -57,11 +57,11 @@ and outputs this quantity to a file called colvar. \verbatim tt: TETRAHEDRAL SPECIES=1-64 SWITCH={RATIONAL D_0=1.3 R_0=0.2} MEAN PRINT ARG=tt.mean FILE=colvar -\endverbatim +\endverbatim The following command calculates the number of tetrahedrality parameters that are greater than 0.8 in a set of 10 atoms. In this calculation it is assumed that there are two atom types A and B and that the first coordination sphere of the -10 atoms of type A contains atoms of type B. The formula above is thus calculated for ten different A atoms and within +10 atoms of type A contains atoms of type B. The formula above is thus calculated for ten different A atoms and within it the sum over \f$j\f$ runs over 40 atoms of type B that could be in the first coordination sphere. \verbatim @@ -82,43 +82,43 @@ public: PLUMED_REGISTER_ACTION(Tetrahedral,"TETRAHEDRAL") -void Tetrahedral::registerKeywords( Keywords& keys ){ +void Tetrahedral::registerKeywords( Keywords& keys ) { CubicHarmonicBase::registerKeywords( keys ); } Tetrahedral::Tetrahedral(const ActionOptions&ao): -Action(ao), -CubicHarmonicBase(ao) + Action(ao), + CubicHarmonicBase(ao) { checkRead(); } double Tetrahedral::calculateCubicHarmonic( const Vector& distance, const double& d2, Vector& myder ) const { - double sp1 = +distance[0]+distance[1]+distance[2]; - double sp2 = +distance[0]-distance[1]-distance[2]; - double sp3 = -distance[0]+distance[1]-distance[2]; - double sp4 = -distance[0]-distance[1]+distance[2]; - - double sp1c = pow( sp1, 3 ); - double sp2c = pow( sp2, 3 ); - double sp3c = pow( sp3, 3 ); - double sp4c = pow( sp4, 3 ); - - double d1 = distance.modulo(); - double r3 = pow( d1, 3 ); - double r5 = pow( d1, 5 ); - - double tmp = sp1c/r3 + sp2c/r3 + sp3c/r3 + sp4c/r3; - - double t1=(3*sp1c)/r5; double tt1=((3*sp1*sp1)/r3); - double t2=(3*sp2c)/r5; double tt2=((3*sp2*sp2)/r3); - double t3=(3*sp3c)/r5; double tt3=((3*sp3*sp3)/r3); - double t4=(3*sp4c)/r5; double tt4=((3*sp4*sp4)/r3); - - myder[0] = (tt1-(distance[0]*t1)) + (tt2-(distance[0]*t2)) + (-tt3-(distance[0]*t3)) + (-tt4-(distance[0]*t4)); - myder[1] = (tt1-(distance[1]*t1)) + (-tt2-(distance[1]*t2)) + (tt3-(distance[1]*t3)) + (-tt4-(distance[1]*t4)); - myder[2] = (tt1-(distance[2]*t1)) + (-tt2-(distance[2]*t2)) + (-tt3-(distance[2]*t3)) + (tt4-(distance[2]*t4)); - + double sp1 = +distance[0]+distance[1]+distance[2]; + double sp2 = +distance[0]-distance[1]-distance[2]; + double sp3 = -distance[0]+distance[1]-distance[2]; + double sp4 = -distance[0]-distance[1]+distance[2]; + + double sp1c = pow( sp1, 3 ); + double sp2c = pow( sp2, 3 ); + double sp3c = pow( sp3, 3 ); + double sp4c = pow( sp4, 3 ); + + double d1 = distance.modulo(); + double r3 = pow( d1, 3 ); + double r5 = pow( d1, 5 ); + + double tmp = sp1c/r3 + sp2c/r3 + sp3c/r3 + sp4c/r3; + + double t1=(3*sp1c)/r5; double tt1=((3*sp1*sp1)/r3); + double t2=(3*sp2c)/r5; double tt2=((3*sp2*sp2)/r3); + double t3=(3*sp3c)/r5; double tt3=((3*sp3*sp3)/r3); + double t4=(3*sp4c)/r5; double tt4=((3*sp4*sp4)/r3); + + myder[0] = (tt1-(distance[0]*t1)) + (tt2-(distance[0]*t2)) + (-tt3-(distance[0]*t3)) + (-tt4-(distance[0]*t4)); + myder[1] = (tt1-(distance[1]*t1)) + (-tt2-(distance[1]*t2)) + (tt3-(distance[1]*t3)) + (-tt4-(distance[1]*t4)); + myder[2] = (tt1-(distance[2]*t1)) + (-tt2-(distance[2]*t2)) + (-tt3-(distance[2]*t3)) + (tt4-(distance[2]*t4)); + return tmp; } diff --git a/src/crystallization/VectorMean.cpp b/src/crystallization/VectorMean.cpp index 9130b0d7c..5359586b1 100644 --- a/src/crystallization/VectorMean.cpp +++ b/src/crystallization/VectorMean.cpp @@ -43,69 +43,69 @@ public: PLUMED_REGISTER_VESSEL(VectorMean,"VMEAN") -void VectorMean::registerKeywords( Keywords& keys ){ +void VectorMean::registerKeywords( Keywords& keys ) { vesselbase::FunctionVessel::registerKeywords(keys); } -void VectorMean::reserveKeyword( Keywords& keys ){ +void VectorMean::reserveKeyword( Keywords& keys ) { keys.reserve("vessel","VMEAN","calculate the norm of the mean vector."); keys.addOutputComponent("vmean","VMEAN","the norm of the mean vector. The output component can be refererred to elsewhere in the input " - "file by using the label.vmean"); + "file by using the label.vmean"); } VectorMean::VectorMean( const vesselbase::VesselOptions& da ) : -FunctionVessel(da), -nder(0) + FunctionVessel(da), + nder(0) { } -std::string VectorMean::value_descriptor(){ +std::string VectorMean::value_descriptor() { return "the norm of the mean vector"; } -void VectorMean::resize(){ +void VectorMean::resize() { unsigned ncomp=getAction()->getNumberOfQuantities() - 2; - if( getAction()->derivativesAreRequired() ){ - nder=getAction()->getNumberOfDerivatives(); - resizeBuffer( (1+nder)*(ncomp+1) ); getFinalValue()->resizeDerivatives( nder ); + if( getAction()->derivativesAreRequired() ) { + nder=getAction()->getNumberOfDerivatives(); + resizeBuffer( (1+nder)*(ncomp+1) ); getFinalValue()->resizeDerivatives( nder ); } else { - nder=0; resizeBuffer(ncomp+1); + nder=0; resizeBuffer(ncomp+1); } } void VectorMean::calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const { unsigned ncomp=getAction()->getNumberOfQuantities()-2; - double weight=myvals.get(0); plumed_dbg_assert( weight>=getTolerance() ); + double weight=myvals.get(0); plumed_dbg_assert( weight>=getTolerance() ); buffer[bufstart] += weight; - for(unsigned i=0;i<ncomp;++i) buffer[bufstart + (1+i)*(1+nder)] += weight*myvals.get(2+i); + for(unsigned i=0; i<ncomp; ++i) buffer[bufstart + (1+i)*(1+nder)] += weight*myvals.get(2+i); if( !getAction()->derivativesAreRequired() ) return; if( diffweight ) myvals.chainRule( 0, 0, 1, 0, 1.0, bufstart, buffer ); - for(unsigned i=0;i<ncomp;++i){ - double colvar=myvals.get(2+i); - myvals.chainRule( 2+i, 1+i, 1, 0, weight, bufstart, buffer ); - if( diffweight ) myvals.chainRule( 0, 1+i, 1, 0, colvar, bufstart, buffer ); + for(unsigned i=0; i<ncomp; ++i) { + double colvar=myvals.get(2+i); + myvals.chainRule( 2+i, 1+i, 1, 0, weight, bufstart, buffer ); + if( diffweight ) myvals.chainRule( 0, 1+i, 1, 0, colvar, bufstart, buffer ); } return; } -void VectorMean::finish( const std::vector<double>& buffer ){ +void VectorMean::finish( const std::vector<double>& buffer ) { unsigned ncomp=getAction()->getNumberOfQuantities()-2; - double sum=0, ww=buffer[bufstart]; - for(unsigned i=0;i<ncomp;++i){ - double tmp = buffer[bufstart+(nder+1)*(i+1)] / ww; - sum+=tmp*tmp; + double sum=0, ww=buffer[bufstart]; + for(unsigned i=0; i<ncomp; ++i) { + double tmp = buffer[bufstart+(nder+1)*(i+1)] / ww; + sum+=tmp*tmp; } - setOutputValue( sqrt(sum) ); + setOutputValue( sqrt(sum) ); if( !getAction()->derivativesAreRequired() ) return; Value* fval=getFinalValue(); double tw = 1.0 / sqrt(sum); - for(unsigned icomp=0;icomp<ncomp;++icomp){ - double tmp = buffer[bufstart + (icomp+1)*(1+nder)] / ww; - unsigned bstart = bufstart + (1+icomp)*(nder+1) + 1; - for(unsigned jder=0;jder<nder;++jder) fval->addDerivative( jder, (tw*tmp/ww)*( buffer[bstart + jder] - tmp*buffer[bufstart + 1 + jder] ) ); + for(unsigned icomp=0; icomp<ncomp; ++icomp) { + double tmp = buffer[bufstart + (icomp+1)*(1+nder)] / ww; + unsigned bstart = bufstart + (1+icomp)*(nder+1) + 1; + for(unsigned jder=0; jder<nder; ++jder) fval->addDerivative( jder, (tw*tmp/ww)*( buffer[bstart + jder] - tmp*buffer[bufstart + 1 + jder] ) ); } } diff --git a/src/crystallization/VectorMultiColvar.cpp b/src/crystallization/VectorMultiColvar.cpp index e3bd4d4d5..9a070de58 100644 --- a/src/crystallization/VectorMultiColvar.cpp +++ b/src/crystallization/VectorMultiColvar.cpp @@ -25,24 +25,24 @@ namespace PLMD { namespace crystallization { -void VectorMultiColvar::registerKeywords( Keywords& keys ){ +void VectorMultiColvar::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); } VectorMultiColvar::VectorMultiColvar(const ActionOptions& ao): -Action(ao), -MultiColvarBase(ao), -store_director(true) + Action(ao), + MultiColvarBase(ao), + store_director(true) { setLowMemOption(true); } -void VectorMultiColvar::setVectorDimensionality( const unsigned& ncomp ){ +void VectorMultiColvar::setVectorDimensionality( const unsigned& ncomp ) { ncomponents = ncomp; resizeFunctions(); // This resize needs to be here to ensure buffers are set to correct size in base } -void VectorMultiColvar::doNotCalculateDirector(){ - store_director=false; // Need a sanity check in here so that you don't use the same instance of Q4 to calcualte vectors and directors +void VectorMultiColvar::doNotCalculateDirector() { + store_director=false; // Need a sanity check in here so that you don't use the same instance of Q4 to calcualte vectors and directors } double VectorMultiColvar::compute( const unsigned& taskIndex, multicolvar::AtomValuePack& myatoms ) const { @@ -52,46 +52,46 @@ double VectorMultiColvar::compute( const unsigned& taskIndex, multicolvar::AtomV updateActiveAtoms( myatoms ); // Now calculate the norm of the vector (this is what we return here) - double norm=0; - for(unsigned i=0;i<ncomponents;++i) norm += myatoms.getValue(2+i)*myatoms.getValue(2+i); + double norm=0; + for(unsigned i=0; i<ncomponents; ++i) norm += myatoms.getValue(2+i)*myatoms.getValue(2+i); norm=sqrt(norm); - - if( !doNotCalculateDerivatives() ){ - double inorm = 1.0 / norm; std::vector<double> dervec( ncomponents ); - for(unsigned i=0;i<ncomponents;++i) dervec[i] = inorm*myatoms.getValue(2+i); - - MultiValue& myvals=myatoms.getUnderlyingMultiValue(); - for(unsigned j=0;j<myvals.getNumberActive();++j){ - unsigned jder=myvals.getActiveIndex(j); - for(unsigned i=0;i<ncomponents;++i) myvals.addDerivative( 1, jder, dervec[i]*myvals.getDerivative( 2+i, jder ) ); - } + + if( !doNotCalculateDerivatives() ) { + double inorm = 1.0 / norm; std::vector<double> dervec( ncomponents ); + for(unsigned i=0; i<ncomponents; ++i) dervec[i] = inorm*myatoms.getValue(2+i); + + MultiValue& myvals=myatoms.getUnderlyingMultiValue(); + for(unsigned j=0; j<myvals.getNumberActive(); ++j) { + unsigned jder=myvals.getActiveIndex(j); + for(unsigned i=0; i<ncomponents; ++i) myvals.addDerivative( 1, jder, dervec[i]*myvals.getDerivative( 2+i, jder ) ); + } } - + return norm; } void VectorMultiColvar::normalizeVector( std::vector<double>& vals ) const { double inorm = 1.0; if( vals[1]>epsilon ) inorm = 1.0 / vals[1]; - for(unsigned i=2;i<vals.size();++i) vals[i] = inorm*vals[i]; + for(unsigned i=2; i<vals.size(); ++i) vals[i] = inorm*vals[i]; } void VectorMultiColvar::normalizeVectorDerivatives( MultiValue& myvals ) const { double v = myvals.get(1), weight = 1.0 / v, wdf = 1.0 / ( v*v*v ); - for(unsigned j=0;j<myvals.getNumberActive();++j){ - double comp2=0.0; unsigned jder=myvals.getActiveIndex(j); - for(unsigned jcomp=2;jcomp<myvals.getNumberOfValues();++jcomp) comp2 += myvals.get(jcomp)*myvals.getDerivative( jcomp, jder ); - for(unsigned jcomp=2;jcomp<myvals.getNumberOfValues();++jcomp){ - myvals.setDerivative( jcomp, jder, weight*myvals.getDerivative( jcomp, jder ) - wdf*comp2*myvals.get(jcomp) ); - } + for(unsigned j=0; j<myvals.getNumberActive(); ++j) { + double comp2=0.0; unsigned jder=myvals.getActiveIndex(j); + for(unsigned jcomp=2; jcomp<myvals.getNumberOfValues(); ++jcomp) comp2 += myvals.get(jcomp)*myvals.getDerivative( jcomp, jder ); + for(unsigned jcomp=2; jcomp<myvals.getNumberOfValues(); ++jcomp) { + myvals.setDerivative( jcomp, jder, weight*myvals.getDerivative( jcomp, jder ) - wdf*comp2*myvals.get(jcomp) ); + } } } -void VectorMultiColvar::addForcesOnAtoms( const std::vector<double>& inforces ){ +void VectorMultiColvar::addForcesOnAtoms( const std::vector<double>& inforces ) { plumed_dbg_assert( inforces.size()==getNumberOfDerivatives() ); - std::vector<double> oldforces( getNumberOfDerivatives() ); - getForcesFromVessels( oldforces ); - for(unsigned i=0;i<getNumberOfDerivatives();++i) oldforces[i]+=inforces[i]; + std::vector<double> oldforces( getNumberOfDerivatives() ); + getForcesFromVessels( oldforces ); + for(unsigned i=0; i<getNumberOfDerivatives(); ++i) oldforces[i]+=inforces[i]; setForcesOnAtoms( oldforces ); } diff --git a/src/crystallization/VectorMultiColvar.h b/src/crystallization/VectorMultiColvar.h index ab0ca9b3b..b41f0d84a 100644 --- a/src/crystallization/VectorMultiColvar.h +++ b/src/crystallization/VectorMultiColvar.h @@ -30,8 +30,8 @@ namespace PLMD { namespace crystallization { class VectorMultiColvar : public multicolvar::MultiColvarBase { -friend class OrientationSphere; -friend class VolumeGradientBase; + friend class OrientationSphere; + friend class VolumeGradientBase; private: /// Are we storing the director of the vector of the vector bool store_director; @@ -47,9 +47,9 @@ protected: public: static void registerKeywords( Keywords& keys ); explicit VectorMultiColvar(const ActionOptions&); - ~VectorMultiColvar(){} + ~VectorMultiColvar() {} /// The norm of a vector is not periodic - virtual bool isPeriodic(){ return false; } + virtual bool isPeriodic() { return false; } /// Calculate the multicolvar // double doCalculation( const unsigned& taskIndex, multicolvar::AtomValuePack& myatoms ) const ; /// This shouldn't do anything @@ -65,13 +65,13 @@ public: /// This makes sure we are not calculating the director when we do LocalAverage virtual void doNotCalculateDirector(); /// This does normalizeing of vectors for storeDataVessel - virtual void normalizeVector( std::vector<double>& vals ) const ; - virtual void normalizeVectorDerivatives( MultiValue& myvals ) const ; + virtual void normalizeVector( std::vector<double>& vals ) const ; + virtual void normalizeVectorDerivatives( MultiValue& myvals ) const ; }; inline unsigned VectorMultiColvar::getNumberOfComponentsInVector() const { - return ncomponents; + return ncomponents; } inline diff --git a/src/crystallization/VectorSum.cpp b/src/crystallization/VectorSum.cpp index 2c0eb346f..ca0eaf652 100644 --- a/src/crystallization/VectorSum.cpp +++ b/src/crystallization/VectorSum.cpp @@ -43,70 +43,70 @@ public: PLUMED_REGISTER_VESSEL(VectorSum,"VSUM") -void VectorSum::registerKeywords( Keywords& keys ){ +void VectorSum::registerKeywords( Keywords& keys ) { vesselbase::FunctionVessel::registerKeywords(keys); } -void VectorSum::reserveKeyword( Keywords& keys ){ +void VectorSum::reserveKeyword( Keywords& keys ) { keys.reserve("vessel","VSUM","calculate the norm of the sum of vectors."); keys.addOutputComponent("vsum","VSUM","the norm of sum of vectors. The output component can be refererred to elsewhere in the input " - "file by using the label.vsum"); + "file by using the label.vsum"); } VectorSum::VectorSum( const vesselbase::VesselOptions& da ) : -FunctionVessel(da), -nder(0) + FunctionVessel(da), + nder(0) { } -std::string VectorSum::value_descriptor(){ +std::string VectorSum::value_descriptor() { return "the norm of the mean vector"; } -void VectorSum::resize(){ +void VectorSum::resize() { unsigned ncomp=getAction()->getNumberOfQuantities() - 2; - if( getAction()->derivativesAreRequired() ){ - nder=getAction()->getNumberOfDerivatives(); - resizeBuffer( (1+nder)*ncomp ); getFinalValue()->resizeDerivatives( nder ); + if( getAction()->derivativesAreRequired() ) { + nder=getAction()->getNumberOfDerivatives(); + resizeBuffer( (1+nder)*ncomp ); getFinalValue()->resizeDerivatives( nder ); } else { - nder=0; resizeBuffer(ncomp); + nder=0; resizeBuffer(ncomp); } } void VectorSum::calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const { unsigned ncomp=getAction()->getNumberOfQuantities()-2; - double weight=myvals.get(0); + double weight=myvals.get(0); plumed_dbg_assert( weight>=getTolerance() ); - for(unsigned i=0;i<ncomp;++i) buffer[bufstart + i*(1+nder)] += weight*myvals.get(2+i); + for(unsigned i=0; i<ncomp; ++i) buffer[bufstart + i*(1+nder)] += weight*myvals.get(2+i); if( !getAction()->derivativesAreRequired() ) return; - for(unsigned i=0;i<ncomp;++i){ - double colvar=myvals.get(2+i); - myvals.chainRule( 2+i, i, 1, 0, weight, bufstart, buffer ); - if( diffweight ) myvals.chainRule( 0, i, 1, 0, colvar, bufstart, buffer ); + for(unsigned i=0; i<ncomp; ++i) { + double colvar=myvals.get(2+i); + myvals.chainRule( 2+i, i, 1, 0, weight, bufstart, buffer ); + if( diffweight ) myvals.chainRule( 0, i, 1, 0, colvar, bufstart, buffer ); } return; } -void VectorSum::finish( const std::vector<double>& buffer ){ +void VectorSum::finish( const std::vector<double>& buffer ) { unsigned ncomp=getAction()->getNumberOfQuantities()-2; - double sum=0; - for(unsigned i=0;i<ncomp;++i){ - double tmp = buffer[bufstart+(nder+1)*i]; - sum+=tmp*tmp; + double sum=0; + for(unsigned i=0; i<ncomp; ++i) { + double tmp = buffer[bufstart+(nder+1)*i]; + sum+=tmp*tmp; } double tw = 1.0 / sqrt(sum); - setOutputValue( sqrt(sum) ); + setOutputValue( sqrt(sum) ); if( !getAction()->derivativesAreRequired() ) return; Value* fval=getFinalValue(); - for(unsigned icomp=0;icomp<ncomp;++icomp){ - double tmp = buffer[bufstart + icomp*(1+nder)]; - unsigned bstart = bufstart + icomp*(nder+1) + 1; - for(unsigned jder=0;jder<nder;++jder) fval->addDerivative( jder, tw*tmp*buffer[bstart + jder] ); + for(unsigned icomp=0; icomp<ncomp; ++icomp) { + double tmp = buffer[bufstart + icomp*(1+nder)]; + unsigned bstart = bufstart + icomp*(nder+1) + 1; + for(unsigned jder=0; jder<nder; ++jder) fval->addDerivative( jder, tw*tmp*buffer[bstart + jder] ); } } diff --git a/src/eds/EDS.cpp b/src/eds/EDS.cpp index 9d8187555..e5e575abe 100644 --- a/src/eds/EDS.cpp +++ b/src/eds/EDS.cpp @@ -104,7 +104,7 @@ eds: EDS ARG=dist,dist2 CENTER=2.0,1.0 PERIOD=50000 TEMP=1.0 IN_RESTART=restart. */ //+ENDPLUMEDOC -class EDS : public Bias{ +class EDS : public Bias { private: @@ -160,7 +160,7 @@ private: void calc_ssd_step_size(); void reset_statistics(); void update_bias(); - void apply_bias(); + void apply_bias(); public: explicit EDS(const ActionOptions&); @@ -171,616 +171,617 @@ public: ~EDS(); }; - PLUMED_REGISTER_ACTION(EDS,"EDS") - - void EDS::registerKeywords(Keywords& keys){ - Bias::registerKeywords(keys); - keys.use("ARG"); - keys.add("optional","CENTER","The desired centers (equilibrium values) which will be sought during the adaptive linear biasing. This is for fixed values"); - keys.add("optional","CENTER_ARG","The desired centers (equilibrium values) which will be sought during the adaptive linear biasing. " - "CENTER_ARG is for calculated centers, e.g. from a CV or analysis. "); - - keys.add("compulsory","PERIOD","Steps over which to adjust bias"); - - keys.add("compulsory","RANGE","3.0","The largest magnitude of the force constant which one expects (in kBT) for each CV based"); - keys.add("compulsory","SEED","0","Seed for random order of changing bias"); - keys.add("compulsory","INIT","0","Starting value for coupling coefficients"); - keys.add("compulsory","FIXED","0","Fixed target values for bias factors (not adaptive)"); - keys.add("optional","BIAS_SCALE","A divisor to set the units of the bias. " - "If not set, this will be the experimental value by default (as is done in White and Voth 2014)."); - keys.add("optional","TEMP","The system temperature. If not provided will be taken from MD code (if available)"); - keys.add("optional","MULTI_PROP","What proportion of dimensions to update at each step. " - "Must be in interval [1,0), where 1 indicates all and any other indicates a stochastic update. " - "If not set, default is 1 / N, where N is the number of CVs. "); - keys.add("optional","RESTART_FMT","the format that should be used to output real numbers in EDS restarts"); - keys.add("optional","OUT_RESTART","Output file for all information needed to continue EDS simulation. " - "If you have the RESTART directive set (global or for EDS), this file will be appended to. " - "Note that the header will be printed again if appending."); - keys.add("optional","IN_RESTART","Read this file to continue an EDS simulation. " - "If same as OUT_RESTART and you have not set the RESTART directive, the file will be backed-up and overwritten with new output. " - "If you do have the RESTART flag set and it is the same name as OUT_RESTART, this file will be appended."); - - keys.addFlag("RAMP",false,"Slowly increase bias constant to a fixed value"); - keys.addFlag("COVAR",false,"Utilize the covariance matrix when updating the bias. Default Off, but may be enabled due to other options"); - keys.addFlag("FREEZE",false,"Fix bias at current level (only used for restarting). Can also set PERIOD=0 if not using RESTART."); - keys.addFlag("MEAN",false,"Instead of using final bias level from restart, use average. Can only be used in conjunction with FREEZE"); - - keys.use("RESTART"); - - keys.addOutputComponent("force2","default","squared value of force from the bias"); - keys.addOutputComponent("_coupling","default", "For each named CV biased, there will be a corresponding output CV_coupling storing the current linear bias prefactor."); +PLUMED_REGISTER_ACTION(EDS,"EDS") + +void EDS::registerKeywords(Keywords& keys) { + Bias::registerKeywords(keys); + keys.use("ARG"); + keys.add("optional","CENTER","The desired centers (equilibrium values) which will be sought during the adaptive linear biasing. This is for fixed values"); + keys.add("optional","CENTER_ARG","The desired centers (equilibrium values) which will be sought during the adaptive linear biasing. " + "CENTER_ARG is for calculated centers, e.g. from a CV or analysis. "); + + keys.add("compulsory","PERIOD","Steps over which to adjust bias"); + + keys.add("compulsory","RANGE","3.0","The largest magnitude of the force constant which one expects (in kBT) for each CV based"); + keys.add("compulsory","SEED","0","Seed for random order of changing bias"); + keys.add("compulsory","INIT","0","Starting value for coupling coefficients"); + keys.add("compulsory","FIXED","0","Fixed target values for bias factors (not adaptive)"); + keys.add("optional","BIAS_SCALE","A divisor to set the units of the bias. " + "If not set, this will be the experimental value by default (as is done in White and Voth 2014)."); + keys.add("optional","TEMP","The system temperature. If not provided will be taken from MD code (if available)"); + keys.add("optional","MULTI_PROP","What proportion of dimensions to update at each step. " + "Must be in interval [1,0), where 1 indicates all and any other indicates a stochastic update. " + "If not set, default is 1 / N, where N is the number of CVs. "); + keys.add("optional","RESTART_FMT","the format that should be used to output real numbers in EDS restarts"); + keys.add("optional","OUT_RESTART","Output file for all information needed to continue EDS simulation. " + "If you have the RESTART directive set (global or for EDS), this file will be appended to. " + "Note that the header will be printed again if appending."); + keys.add("optional","IN_RESTART","Read this file to continue an EDS simulation. " + "If same as OUT_RESTART and you have not set the RESTART directive, the file will be backed-up and overwritten with new output. " + "If you do have the RESTART flag set and it is the same name as OUT_RESTART, this file will be appended."); + + keys.addFlag("RAMP",false,"Slowly increase bias constant to a fixed value"); + keys.addFlag("COVAR",false,"Utilize the covariance matrix when updating the bias. Default Off, but may be enabled due to other options"); + keys.addFlag("FREEZE",false,"Fix bias at current level (only used for restarting). Can also set PERIOD=0 if not using RESTART."); + keys.addFlag("MEAN",false,"Instead of using final bias level from restart, use average. Can only be used in conjunction with FREEZE"); + + keys.use("RESTART"); + + keys.addOutputComponent("force2","default","squared value of force from the bias"); + keys.addOutputComponent("_coupling","default", "For each named CV biased, there will be a corresponding output CV_coupling storing the current linear bias prefactor."); +} + +EDS::EDS(const ActionOptions&ao): + PLUMED_BIAS_INIT(ao), + ncvs_(getNumberOfArguments()), + scale_(ncvs_,0.0), + current_coupling_(ncvs_,0.0), + set_coupling_(ncvs_,0.0), + target_coupling_(ncvs_,0.0), + max_coupling_range_(ncvs_,3.0), + max_coupling_grad_(ncvs_,0.0), + coupling_rate_(ncvs_,1.0), + coupling_accum_(ncvs_,1.0), + means_(ncvs_,0.0), + step_size_(ncvs_,0.0), + out_coupling_(ncvs_,NULL), + in_restart_name_(""), + out_restart_name_(""), + fmt_("%f"), + b_adaptive_(true), + b_freeze_(false), + b_equil_(true), + b_ramp_(false), + b_covar_(false), + b_restart_(false), + b_write_restart_(false), + b_hard_c_range_(false), + seed_(0), + update_period_(0), + avg_coupling_count_(1), + update_calls_(0), + kbt_(0.0), + c_range_increase_f_(1.25), + multi_prop_(-1.0), + value_force2_(NULL) +{ + double temp=-1.0; + bool b_mean=false; + + addComponent("force2"); + componentIsNotPeriodic("force2"); + value_force2_ = getPntrToComponent("force2"); + + for(unsigned int i = 0; i<ncvs_; i++) { + std::string comp = getPntrToArgument(i)->getName() + "_coupling"; + addComponent(comp); + componentIsNotPeriodic(comp); + out_coupling_[i]=getPntrToComponent(comp); } - EDS::EDS(const ActionOptions&ao): - PLUMED_BIAS_INIT(ao), - ncvs_(getNumberOfArguments()), - scale_(ncvs_,0.0), - current_coupling_(ncvs_,0.0), - set_coupling_(ncvs_,0.0), - target_coupling_(ncvs_,0.0), - max_coupling_range_(ncvs_,3.0), - max_coupling_grad_(ncvs_,0.0), - coupling_rate_(ncvs_,1.0), - coupling_accum_(ncvs_,1.0), - means_(ncvs_,0.0), - step_size_(ncvs_,0.0), - out_coupling_(ncvs_,NULL), - in_restart_name_(""), - out_restart_name_(""), - fmt_("%f"), - b_adaptive_(true), - b_freeze_(false), - b_equil_(true), - b_ramp_(false), - b_covar_(false), - b_restart_(false), - b_write_restart_(false), - b_hard_c_range_(false), - seed_(0), - update_period_(0), - avg_coupling_count_(1), - update_calls_(0), - kbt_(0.0), - c_range_increase_f_(1.25), - multi_prop_(-1.0), - value_force2_(NULL) - { - double temp=-1.0; - bool b_mean=false; - - addComponent("force2"); - componentIsNotPeriodic("force2"); - value_force2_ = getPntrToComponent("force2"); - - for(unsigned int i = 0;i<ncvs_;i++){ - std::string comp = getPntrToArgument(i)->getName() + "_coupling"; - addComponent(comp); - componentIsNotPeriodic(comp); - out_coupling_[i]=getPntrToComponent(comp); - } - - parseVector("CENTER",center_); - parseArgumentList("CENTER_ARG",center_values_); - parseVector("BIAS_SCALE", scale_); - parseVector("RANGE",max_coupling_range_); - parseVector("FIXED",target_coupling_); - parseVector("INIT",set_coupling_); - parse("PERIOD",update_period_); - parse("TEMP",temp); - parse("SEED",seed_); - parse("MULTI_PROP",multi_prop_); - parse("RESTART_FMT", fmt_); - fmt_ = " " + fmt_;//add space since parse strips them - parse("OUT_RESTART",out_restart_name_); - parseFlag("RAMP",b_ramp_); - parseFlag("FREEZE",b_freeze_); - parseFlag("MEAN",b_mean); - parseFlag("COVAR",b_covar_); - parse("IN_RESTART",in_restart_name_); - checkRead(); - - /* - * Things that are different when usnig changing centers: - * 1. Scale - * 2. The log file - * 3. Reading Restarts - */ - - if(center_.size() == 0) { - if(center_values_.size() == 0) - error("Must set either CENTER or CENTER_ARG"); - else if(center_values_.size() != ncvs_) - error("CENTER_ARG must contain the same number of variables as ARG"); - b_c_values_ = true; - center_.resize(ncvs_); - log.printf(" EDS will use possibly varying centers\n"); - } else { - if(center_.size() != ncvs_) - error("Must have same number of CENTER arguments as ARG arguments"); - else if(center_values_.size() != 0) - error("You can only set CENTER or CENTER_ARG. Not both"); - b_c_values_ = false; - log.printf(" EDS will use fixed centers\n"); - } - - - - log.printf(" setting scaling:"); - if(scale_.size() > 0 && scale_.size() < ncvs_) { - error("the number of BIAS_SCALE values be the same as number of CVs"); - } else if(scale_.size() == 0 && b_c_values_) { - log.printf(" Setting SCALE to be 1 for all CVs\n"); - scale_.resize(ncvs_); - for(unsigned int i = 0; i < ncvs_; ++i) - scale_[i] = 1; - } else if(scale_.size() == 0 && !b_c_values_) { - log.printf(" (default) "); - - scale_.resize(ncvs_); - for(unsigned int i = 0; i < scale_.size(); i++) { - if(center_[i]==0) - error("BIAS_SCALE parameter has been set to CENTER value of 0 (as is default). This will divide by 0, so giving up. See doc for EDS bias"); - scale_[i] = center_[i]; - } - } else { - for(unsigned int i = 0; i < scale_.size(); i++) - log.printf(" %f",scale_[i]); - } - log.printf("\n"); + parseVector("CENTER",center_); + parseArgumentList("CENTER_ARG",center_values_); + parseVector("BIAS_SCALE", scale_); + parseVector("RANGE",max_coupling_range_); + parseVector("FIXED",target_coupling_); + parseVector("INIT",set_coupling_); + parse("PERIOD",update_period_); + parse("TEMP",temp); + parse("SEED",seed_); + parse("MULTI_PROP",multi_prop_); + parse("RESTART_FMT", fmt_); + fmt_ = " " + fmt_;//add space since parse strips them + parse("OUT_RESTART",out_restart_name_); + parseFlag("RAMP",b_ramp_); + parseFlag("FREEZE",b_freeze_); + parseFlag("MEAN",b_mean); + parseFlag("COVAR",b_covar_); + parse("IN_RESTART",in_restart_name_); + checkRead(); + + /* + * Things that are different when usnig changing centers: + * 1. Scale + * 2. The log file + * 3. Reading Restarts + */ + + if(center_.size() == 0) { + if(center_values_.size() == 0) + error("Must set either CENTER or CENTER_ARG"); + else if(center_values_.size() != ncvs_) + error("CENTER_ARG must contain the same number of variables as ARG"); + b_c_values_ = true; + center_.resize(ncvs_); + log.printf(" EDS will use possibly varying centers\n"); + } else { + if(center_.size() != ncvs_) + error("Must have same number of CENTER arguments as ARG arguments"); + else if(center_values_.size() != 0) + error("You can only set CENTER or CENTER_ARG. Not both"); + b_c_values_ = false; + log.printf(" EDS will use fixed centers\n"); + } - if(b_covar_) { - log.printf(" EDS will utilize covariance matrix for update steps\n"); - covar_.resize(ncvs_, ncvs_); - } else { - log.printf(" EDS will utilize variance for update steps\n"); - ssds_.resize(ncvs_); - } + log.printf(" setting scaling:"); + if(scale_.size() > 0 && scale_.size() < ncvs_) { + error("the number of BIAS_SCALE values be the same as number of CVs"); + } else if(scale_.size() == 0 && b_c_values_) { + log.printf(" Setting SCALE to be 1 for all CVs\n"); + scale_.resize(ncvs_); + for(unsigned int i = 0; i < ncvs_; ++i) + scale_[i] = 1; + } else if(scale_.size() == 0 && !b_c_values_) { + log.printf(" (default) "); - if (b_mean == true and b_freeze_ == false) { - error("EDS keyworkd MEAN can only be used along with keyword FREEZE"); + scale_.resize(ncvs_); + for(unsigned int i = 0; i < scale_.size(); i++) { + if(center_[i]==0) + error("BIAS_SCALE parameter has been set to CENTER value of 0 (as is default). This will divide by 0, so giving up. See doc for EDS bias"); + scale_[i] = center_[i]; } + } else { + for(unsigned int i = 0; i < scale_.size(); i++) + log.printf(" %f",scale_[i]); + } + log.printf("\n"); - if(in_restart_name_ != ""){ - b_restart_ = true; - log.printf(" reading simulation information from file: %s\n",in_restart_name_.c_str()); - readInRestart(b_mean); - } else{ - - if(temp>=0.0) kbt_=plumed.getAtoms().getKBoltzmann()*temp; - else kbt_ = plumed.getAtoms().getKbT(); - - //in driver, this results in kbt of 0 - if(kbt_ == 0){ - error(" Unable to determine valid kBT. " - "Could be because you are runnning from driver or MD didn't give temperature.\n" - "Consider setting temperature manually with the TEMP keyword."); - kbt_ = 1; - } - log.printf(" kBT = %f\n",kbt_); - log.printf(" Updating every %i steps\n",update_period_); - - if(!b_c_values_) { - log.printf(" with centers:"); - for(unsigned int i = 0;i< ncvs_;i++){ - log.printf(" %f ",center_[i]); - } - } else { - log.printf(" with actions centers:"); - for(unsigned int i = 0;i< ncvs_;i++){ - log.printf(" %s ",center_values_[i]->getName().c_str()); - //add dependency on these actions - addDependency(center_values_[i]->getPntrToAction()); - } - } + if(b_covar_) { + log.printf(" EDS will utilize covariance matrix for update steps\n"); + covar_.resize(ncvs_, ncvs_); + } else { + log.printf(" EDS will utilize variance for update steps\n"); + ssds_.resize(ncvs_); + } - log.printf("\n with initial ranges / rates:\n"); - for(unsigned int i = 0;i<max_coupling_range_.size();i++) { - //this is just an empirical guess. Bigger range, bigger grads. Less frequent updates, bigger changes - max_coupling_range_[i]*=kbt_; - max_coupling_grad_[i] = max_coupling_range_[i]*update_period_/100.; - log.printf(" %f / %f\n",max_coupling_range_[i],max_coupling_grad_[i]); - } - if(seed_>0){ - log.printf(" setting random seed = %i",seed_); - rand_.setSeed(seed_); - } + if (b_mean == true and b_freeze_ == false) { + error("EDS keyworkd MEAN can only be used along with keyword FREEZE"); + } - for(unsigned int i = 0;i<ncvs_;++i) if(target_coupling_[i]!=0.0) b_adaptive_=false; + if(in_restart_name_ != "") { + b_restart_ = true; + log.printf(" reading simulation information from file: %s\n",in_restart_name_.c_str()); + readInRestart(b_mean); + } else { + + if(temp>=0.0) kbt_=plumed.getAtoms().getKBoltzmann()*temp; + else kbt_ = plumed.getAtoms().getKbT(); + + //in driver, this results in kbt of 0 + if(kbt_ == 0) { + error(" Unable to determine valid kBT. " + "Could be because you are runnning from driver or MD didn't give temperature.\n" + "Consider setting temperature manually with the TEMP keyword."); + kbt_ = 1; + } - if(!b_adaptive_){ - if(b_ramp_) { - log.printf(" ramping up coupling constants over %i steps\n",update_period_); - } + log.printf(" kBT = %f\n",kbt_); + log.printf(" Updating every %i steps\n",update_period_); - log.printf(" with starting coupling constants"); - for(unsigned int i = 0;i<set_coupling_.size();i++) log.printf(" %f",set_coupling_[i]); - log.printf("\n"); - log.printf(" and final coupling constants"); - for(unsigned int i = 0;i<target_coupling_.size();i++) log.printf(" %f",target_coupling_[i]); - log.printf("\n"); + if(!b_c_values_) { + log.printf(" with centers:"); + for(unsigned int i = 0; i< ncvs_; i++) { + log.printf(" %f ",center_[i]); } - - //now do setup - if(b_ramp_){ - update_period_*=-1; - } - - for(unsigned int i = 0;i<set_coupling_.size();i++) current_coupling_[i] = set_coupling_[i]; - - // if b_adaptive_, then first half will be used for equilibrating and second half for statistics - if(update_period_>0){ - update_period_ /= 2; + } else { + log.printf(" with actions centers:"); + for(unsigned int i = 0; i< ncvs_; i++) { + log.printf(" %s ",center_values_[i]->getName().c_str()); + //add dependency on these actions + addDependency(center_values_[i]->getPntrToAction()); } - - } - if(b_freeze_){ - b_adaptive_=false; - update_period_ = 0; - if (b_mean) { - log.printf(" freezing bias at the average level from the restart file\n"); - } else{ - log.printf(" freezing bias at current level\n"); - } + log.printf("\n with initial ranges / rates:\n"); + for(unsigned int i = 0; i<max_coupling_range_.size(); i++) { + //this is just an empirical guess. Bigger range, bigger grads. Less frequent updates, bigger changes + max_coupling_range_[i]*=kbt_; + max_coupling_grad_[i] = max_coupling_range_[i]*update_period_/100.; + log.printf(" %f / %f\n",max_coupling_range_[i],max_coupling_grad_[i]); } - if(multi_prop_ == -1.0) { - log.printf(" Will update each dimension stochastically with probability 1 / number of CVs\n"); - multi_prop_ = 1.0 / ncvs_; - } else if(multi_prop_ > 0 && multi_prop_ <= 1.0) { - log.printf(" Will update each dimension stochastically with probability %f\n", multi_prop_); - } else{ - error(" MULTI_PROP must be between 0 and 1\n"); + if(seed_>0) { + log.printf(" setting random seed = %i",seed_); + rand_.setSeed(seed_); } - if(out_restart_name_.length()>0) { - log.printf(" writing restart information every %i steps to file %s with format %s\n",abs(update_period_),out_restart_name_.c_str(), fmt_.c_str()); - b_write_restart_ = true; - setupOutRestart(); - } + for(unsigned int i = 0; i<ncvs_; ++i) if(target_coupling_[i]!=0.0) b_adaptive_=false; - log<<" Bibliography "<<plumed.cite("White and Voth, J. Chem. Theory Comput. 10 (8), 3023-3030 (2014)")<<"\n"; - } + if(!b_adaptive_) { + if(b_ramp_) { + log.printf(" ramping up coupling constants over %i steps\n",update_period_); + } - void EDS::readInRestart(const bool b_mean){ - int adaptive_i; + log.printf(" with starting coupling constants"); + for(unsigned int i = 0; i<set_coupling_.size(); i++) log.printf(" %f",set_coupling_[i]); + log.printf("\n"); + log.printf(" and final coupling constants"); + for(unsigned int i = 0; i<target_coupling_.size(); i++) log.printf(" %f",target_coupling_[i]); + log.printf("\n"); + } - in_restart_.open(in_restart_name_); + //now do setup + if(b_ramp_) { + update_period_*=-1; + } - //some sample code to get the field names: - /* - std::vector<std::string> fields; - in_restart_.scanFieldList(fields); - log.printf("field"); - for(unsigned int i = 0;i<fields.size();i++) log.printf(" %s",fields[i].c_str()); - log.printf("\n"); - */ + for(unsigned int i = 0; i<set_coupling_.size(); i++) current_coupling_[i] = set_coupling_[i]; - if(in_restart_.FieldExist("kbt")){ - in_restart_.scanField("kbt",kbt_); - }else{ error("No field 'kbt' in restart file"); } - log.printf(" with kBT = %f\n",kbt_); + // if b_adaptive_, then first half will be used for equilibrating and second half for statistics + if(update_period_>0) { + update_period_ /= 2; + } - if(in_restart_.FieldExist("update_period")){ - in_restart_.scanField("update_period",update_period_); - }else{ error("No field 'update_period' in restart file"); } - log.printf(" Updating every %i steps\n",update_period_); - if(in_restart_.FieldExist("adaptive")){ - //note, no version of scanField for boolean - in_restart_.scanField("adaptive",adaptive_i); - }else{ error("No field 'adaptive' in restart file"); } - b_adaptive_ = bool(adaptive_i); + } - if(in_restart_.FieldExist("seed")){ - in_restart_.scanField("seed",seed_); - }else{ error("No field 'seed' in restart file"); } - if(seed_>0){ - log.printf(" setting random seed = %i",seed_); - rand_.setSeed(seed_); + if(b_freeze_) { + b_adaptive_=false; + update_period_ = 0; + if (b_mean) { + log.printf(" freezing bias at the average level from the restart file\n"); + } else { + log.printf(" freezing bias at current level\n"); } + } - double time; - std::vector<double> avg_bias = std::vector<double>(center_.size()); - unsigned int N = 0; - std::string cv_name; + if(multi_prop_ == -1.0) { + log.printf(" Will update each dimension stochastically with probability 1 / number of CVs\n"); + multi_prop_ = 1.0 / ncvs_; + } else if(multi_prop_ > 0 && multi_prop_ <= 1.0) { + log.printf(" Will update each dimension stochastically with probability %f\n", multi_prop_); + } else { + error(" MULTI_PROP must be between 0 and 1\n"); + } - while(in_restart_.scanField("time",time)){ + if(out_restart_name_.length()>0) { + log.printf(" writing restart information every %i steps to file %s with format %s\n",abs(update_period_),out_restart_name_.c_str(), fmt_.c_str()); + b_write_restart_ = true; + setupOutRestart(); + } - for(unsigned int i = 0;i<ncvs_;++i) { - cv_name = getPntrToArgument(i)->getName(); - in_restart_.scanField(cv_name + "_center", set_coupling_[i]); - in_restart_.scanField(cv_name + "_set", set_coupling_[i]); - in_restart_.scanField(cv_name + "_target",target_coupling_[i]); - in_restart_.scanField(cv_name + "_coupling",current_coupling_[i]); - in_restart_.scanField(cv_name + "_maxrange",max_coupling_range_[i]); - in_restart_.scanField(cv_name + "_maxgrad",max_coupling_grad_[i]); + log<<" Bibliography "<<plumed.cite("White and Voth, J. Chem. Theory Comput. 10 (8), 3023-3030 (2014)")<<"\n"; +} - avg_bias[i] += current_coupling_[i]; - } - N++; +void EDS::readInRestart(const bool b_mean) { + int adaptive_i; - in_restart_.scanField(); - } + in_restart_.open(in_restart_name_); + //some sample code to get the field names: + /* + std::vector<std::string> fields; + in_restart_.scanFieldList(fields); + log.printf("field"); + for(unsigned int i = 0;i<fields.size();i++) log.printf(" %s",fields[i].c_str()); + log.printf("\n"); + */ + + if(in_restart_.FieldExist("kbt")) { + in_restart_.scanField("kbt",kbt_); + } else { error("No field 'kbt' in restart file"); } + log.printf(" with kBT = %f\n",kbt_); + + if(in_restart_.FieldExist("update_period")) { + in_restart_.scanField("update_period",update_period_); + } else { error("No field 'update_period' in restart file"); } + log.printf(" Updating every %i steps\n",update_period_); + + if(in_restart_.FieldExist("adaptive")) { + //note, no version of scanField for boolean + in_restart_.scanField("adaptive",adaptive_i); + } else { error("No field 'adaptive' in restart file"); } + b_adaptive_ = bool(adaptive_i); + + if(in_restart_.FieldExist("seed")) { + in_restart_.scanField("seed",seed_); + } else { error("No field 'seed' in restart file"); } + if(seed_>0) { + log.printf(" setting random seed = %i",seed_); + rand_.setSeed(seed_); + } - log.printf(" with centers:"); - for(unsigned int i = 0;i<center_.size();i++) { - log.printf(" %f",center_[i]); - } - log.printf("\n and scaling:"); - for(unsigned int i = 0;i<scale_.size();i++) { - log.printf(" %f",scale_[i]); - } + double time; + std::vector<double> avg_bias = std::vector<double>(center_.size()); + unsigned int N = 0; + std::string cv_name; - log.printf("\n with initial ranges / rates:\n"); - for(unsigned int i = 0;i<max_coupling_range_.size();i++) { - log.printf(" %f / %f\n",max_coupling_range_[i],max_coupling_grad_[i]); - } + while(in_restart_.scanField("time",time)) { - if(!b_adaptive_ && update_period_<0){ - log.printf(" ramping up coupling constants over %i steps\n",-update_period_); + for(unsigned int i = 0; i<ncvs_; ++i) { + cv_name = getPntrToArgument(i)->getName(); + in_restart_.scanField(cv_name + "_center", set_coupling_[i]); + in_restart_.scanField(cv_name + "_set", set_coupling_[i]); + in_restart_.scanField(cv_name + "_target",target_coupling_[i]); + in_restart_.scanField(cv_name + "_coupling",current_coupling_[i]); + in_restart_.scanField(cv_name + "_maxrange",max_coupling_range_[i]); + in_restart_.scanField(cv_name + "_maxgrad",max_coupling_grad_[i]); + + avg_bias[i] += current_coupling_[i]; } + N++; - if(b_mean) { - log.printf("Loaded in averages for coupling constants...\n"); - for(unsigned int i = 0;i<current_coupling_.size();i++) current_coupling_[i] = avg_bias[i] / N; - for(unsigned int i = 0;i<current_coupling_.size();i++) set_coupling_[i] = avg_bias[i] / N; - } + in_restart_.scanField(); + } - log.printf(" with current coupling constants:\n "); - for(unsigned int i = 0;i<current_coupling_.size();i++) log.printf(" %f",current_coupling_[i]); - log.printf("\n"); - log.printf(" with initial coupling constants:\n "); - for(unsigned int i = 0;i<set_coupling_.size();i++) log.printf(" %f",set_coupling_[i]); - log.printf("\n"); - log.printf(" and final coupling constants:\n "); - for(unsigned int i = 0;i<target_coupling_.size();i++) log.printf(" %f",target_coupling_[i]); - log.printf("\n"); - in_restart_.close(); + log.printf(" with centers:"); + for(unsigned int i = 0; i<center_.size(); i++) { + log.printf(" %f",center_[i]); + } + log.printf("\n and scaling:"); + for(unsigned int i = 0; i<scale_.size(); i++) { + log.printf(" %f",scale_[i]); } - void EDS::setupOutRestart(){ - out_restart_.link(*this); - out_restart_.fmtField(fmt_); - out_restart_.open(out_restart_name_); - out_restart_.setHeavyFlush(); - - out_restart_.addConstantField("adaptive").printField("adaptive",b_adaptive_); - out_restart_.addConstantField("update_period").printField("update_period",update_period_); - out_restart_.addConstantField("seed").printField("seed",seed_); - out_restart_.addConstantField("kbt").printField("kbt",kbt_); + log.printf("\n with initial ranges / rates:\n"); + for(unsigned int i = 0; i<max_coupling_range_.size(); i++) { + log.printf(" %f / %f\n",max_coupling_range_[i],max_coupling_grad_[i]); + } + if(!b_adaptive_ && update_period_<0) { + log.printf(" ramping up coupling constants over %i steps\n",-update_period_); } - void EDS::writeOutRestart() { - std::string cv_name; - out_restart_.printField("time",getTimeStep()*getStep()); + if(b_mean) { + log.printf("Loaded in averages for coupling constants...\n"); + for(unsigned int i = 0; i<current_coupling_.size(); i++) current_coupling_[i] = avg_bias[i] / N; + for(unsigned int i = 0; i<current_coupling_.size(); i++) set_coupling_[i] = avg_bias[i] / N; + } - for(unsigned int i = 0;i<ncvs_;++i) { - cv_name = getPntrToArgument(i)->getName(); - out_restart_.printField(cv_name + "_center",center_[i]); - out_restart_.printField(cv_name + "_set",set_coupling_[i]); - out_restart_.printField(cv_name + "_target",target_coupling_[i]); - out_restart_.printField(cv_name + "_coupling",current_coupling_[i]); - out_restart_.printField(cv_name + "_maxrange",max_coupling_range_[i]); - out_restart_.printField(cv_name + "_maxgrad",max_coupling_grad_[i]); - } - out_restart_.printField(); + log.printf(" with current coupling constants:\n "); + for(unsigned int i = 0; i<current_coupling_.size(); i++) log.printf(" %f",current_coupling_[i]); + log.printf("\n"); + log.printf(" with initial coupling constants:\n "); + for(unsigned int i = 0; i<set_coupling_.size(); i++) log.printf(" %f",set_coupling_[i]); + log.printf("\n"); + log.printf(" and final coupling constants:\n "); + for(unsigned int i = 0; i<target_coupling_.size(); i++) log.printf(" %f",target_coupling_[i]); + log.printf("\n"); + + in_restart_.close(); +} + +void EDS::setupOutRestart() { + out_restart_.link(*this); + out_restart_.fmtField(fmt_); + out_restart_.open(out_restart_name_); + out_restart_.setHeavyFlush(); + + out_restart_.addConstantField("adaptive").printField("adaptive",b_adaptive_); + out_restart_.addConstantField("update_period").printField("update_period",update_period_); + out_restart_.addConstantField("seed").printField("seed",seed_); + out_restart_.addConstantField("kbt").printField("kbt",kbt_); + +} + +void EDS::writeOutRestart() { + std::string cv_name; + out_restart_.printField("time",getTimeStep()*getStep()); + + for(unsigned int i = 0; i<ncvs_; ++i) { + cv_name = getPntrToArgument(i)->getName(); + out_restart_.printField(cv_name + "_center",center_[i]); + out_restart_.printField(cv_name + "_set",set_coupling_[i]); + out_restart_.printField(cv_name + "_target",target_coupling_[i]); + out_restart_.printField(cv_name + "_coupling",current_coupling_[i]); + out_restart_.printField(cv_name + "_maxrange",max_coupling_range_[i]); + out_restart_.printField(cv_name + "_maxgrad",max_coupling_grad_[i]); } + out_restart_.printField(); +} - void EDS::calculate(){ - - //get center values from action if necessary - if(b_c_values_) - for(unsigned int i = 0; i < ncvs_; ++i) - center_[i] = center_values_[i]->get(); +void EDS::calculate() { - apply_bias(); + //get center values from action if necessary + if(b_c_values_) + for(unsigned int i = 0; i < ncvs_; ++i) + center_[i] = center_values_[i]->get(); - //adjust parameters according to EDS recipe - update_calls_++; + apply_bias(); - //check if we're ramping or doing normal updates and then restart if needed. The ramping check - //is complicated because we could be frozen, finished ramping or not ramping. - //The + 2 is so we have an extra line showing that the bias isn't changing (for my sanity and yours) - if( b_write_restart_){ - if(getStep() == 0 || - ( (update_period_ < 0 && !b_freeze_ && update_calls_ <= fabs(update_period_) + 2) || - (update_period_ > 0 && update_calls_ % update_period_ == 0 ) ) ) - writeOutRestart(); - } + //adjust parameters according to EDS recipe + update_calls_++; - int b_finished_equil_flag = 1; + //check if we're ramping or doing normal updates and then restart if needed. The ramping check + //is complicated because we could be frozen, finished ramping or not ramping. + //The + 2 is so we have an extra line showing that the bias isn't changing (for my sanity and yours) + if( b_write_restart_) { + if(getStep() == 0 || + ( (update_period_ < 0 && !b_freeze_ && update_calls_ <= fabs(update_period_) + 2) || + (update_period_ > 0 && update_calls_ % update_period_ == 0 ) ) ) + writeOutRestart(); + } - //assume forces already applied and saved + int b_finished_equil_flag = 1; + //assume forces already applied and saved - //are we ramping to a constant value and not done equilibrating? - if(update_period_ < 0){ - if(update_calls_ <= fabs(update_period_) && !b_freeze_){ - for(unsigned int i = 0;i < ncvs_; ++i) - current_coupling_[i] += (target_coupling_[i]-set_coupling_[i])/fabs(update_period_); + + //are we ramping to a constant value and not done equilibrating? + if(update_period_ < 0) { + if(update_calls_ <= fabs(update_period_) && !b_freeze_) { + for(unsigned int i = 0; i < ncvs_; ++i) + current_coupling_[i] += (target_coupling_[i]-set_coupling_[i])/fabs(update_period_); + } + //make sure we don't reset update calls + b_finished_equil_flag = 0; + } else if(update_period_ == 0) { //do we have a no-update case? + //not updating + //pass + } else if(!b_equil_) { + //if we aren't wating for the bias to equilibrate, collect data + update_statistics(); + } else { + // equilibrating + //check if we've reached the setpoint + for(unsigned int i = 0; i < ncvs_; ++i) { + if(coupling_rate_[i] == 0 || pow(current_coupling_[i] - set_coupling_[i],2) < pow(coupling_rate_[i],2)) { + b_finished_equil_flag &= 1; } - //make sure we don't reset update calls - b_finished_equil_flag = 0; - } else if(update_period_ == 0){ //do we have a no-update case? - //not updating - //pass - } else if(!b_equil_){ - //if we aren't wating for the bias to equilibrate, collect data - update_statistics(); - } else { - // equilibrating - //check if we've reached the setpoint - for(unsigned int i = 0;i < ncvs_; ++i) { - if(coupling_rate_[i] == 0 || pow(current_coupling_[i] - set_coupling_[i],2) < pow(coupling_rate_[i],2)) { - b_finished_equil_flag &= 1; - } - else{ - current_coupling_[i] += coupling_rate_[i]; - b_finished_equil_flag = 0; - } + else { + current_coupling_[i] += coupling_rate_[i]; + b_finished_equil_flag = 0; } } + } - //Update max coupling range if not hard - if(!b_hard_c_range_) { - for(unsigned int i = 0;i < ncvs_; ++i) { - if(fabs(current_coupling_[i])>max_coupling_range_[i]) { - max_coupling_range_[i]*=c_range_increase_f_; - max_coupling_grad_[i]*=c_range_increase_f_; - } + //Update max coupling range if not hard + if(!b_hard_c_range_) { + for(unsigned int i = 0; i < ncvs_; ++i) { + if(fabs(current_coupling_[i])>max_coupling_range_[i]) { + max_coupling_range_[i]*=c_range_increase_f_; + max_coupling_grad_[i]*=c_range_increase_f_; } } - - //reduce all the flags - if(b_equil_ && b_finished_equil_flag) { - b_equil_ = false; - update_calls_ = 0; - } - - //Now we update coupling constant, if necessary - if(!b_equil_ && update_period_ > 0 && update_calls_ == update_period_ && !b_freeze_) { - update_bias(); - update_calls_ = 0; - avg_coupling_count_++; - b_equil_ = true; //back to equilibration now - } //close update if - - //pass couplings out so they are accessible - for(unsigned int i = 0;i<ncvs_;++i){ - out_coupling_[i]->set(current_coupling_[i]); - } } - void EDS::apply_bias() { - //Compute linear force as in "restraint" - double ene = 0, totf2 = 0, cv, m , f; - - for(unsigned int i = 0; i < ncvs_; ++i) { - cv = difference(i, center_[i], getArgument(i)); - m = current_coupling_[i]; - f = -m; - ene += m*cv; - setOutputForce(i,f); - totf2 += f*f; - }; - - setBias(ene); - value_force2_->set(totf2); - + //reduce all the flags + if(b_equil_ && b_finished_equil_flag) { + b_equil_ = false; + update_calls_ = 0; } - void EDS::update_statistics() { - double s; - std::vector<double> deltas(ncvs_); - //Welford, West, and Hanso online variance method - for(unsigned int i = 0; i < ncvs_; ++i) { - deltas[i] = difference(i,means_[i],getArgument(i)); - means_[i] += deltas[i]/update_calls_; - if(!b_covar_) - ssds_[i] += deltas[i]*difference(i,means_[i],getArgument(i)); - } - if(b_covar_) { - for(unsigned int i = 0; i < ncvs_; ++i) { - for(unsigned int j = i; j < ncvs_; ++j) { - s = (update_calls_ - 1) * deltas[i] * deltas[j] / update_calls_ / update_calls_ - covar_(i,j) / update_calls_; - covar_(i,j) += s; - //do this so we don't double count - covar_(j,i) = covar_(i,j); - } + //Now we update coupling constant, if necessary + if(!b_equil_ && update_period_ > 0 && update_calls_ == update_period_ && !b_freeze_) { + update_bias(); + update_calls_ = 0; + avg_coupling_count_++; + b_equil_ = true; //back to equilibration now + } //close update if + + //pass couplings out so they are accessible + for(unsigned int i = 0; i<ncvs_; ++i) { + out_coupling_[i]->set(current_coupling_[i]); + } +} + +void EDS::apply_bias() { + //Compute linear force as in "restraint" + double ene = 0, totf2 = 0, cv, m, f; + + for(unsigned int i = 0; i < ncvs_; ++i) { + cv = difference(i, center_[i], getArgument(i)); + m = current_coupling_[i]; + f = -m; + ene += m*cv; + setOutputForce(i,f); + totf2 += f*f; + }; + + setBias(ene); + value_force2_->set(totf2); + +} + +void EDS::update_statistics() { + double s; + std::vector<double> deltas(ncvs_); + //Welford, West, and Hanso online variance method + for(unsigned int i = 0; i < ncvs_; ++i) { + deltas[i] = difference(i,means_[i],getArgument(i)); + means_[i] += deltas[i]/update_calls_; + if(!b_covar_) + ssds_[i] += deltas[i]*difference(i,means_[i],getArgument(i)); + } + if(b_covar_) { + for(unsigned int i = 0; i < ncvs_; ++i) { + for(unsigned int j = i; j < ncvs_; ++j) { + s = (update_calls_ - 1) * deltas[i] * deltas[j] / update_calls_ / update_calls_ - covar_(i,j) / update_calls_; + covar_(i,j) += s; + //do this so we don't double count + covar_(j,i) = covar_(i,j); } } } +} - void EDS::reset_statistics() { - for(unsigned int i = 0; i < ncvs_; ++i) { - means_[i] = 0; - if(!b_covar_) - ssds_[i] = 0; - } - if(b_covar_) - for(unsigned int i = 0; i < ncvs_; ++i) - for(unsigned int j = 0; j < ncvs_; ++j) - covar_(i,j) = 0; +void EDS::reset_statistics() { + for(unsigned int i = 0; i < ncvs_; ++i) { + means_[i] = 0; + if(!b_covar_) + ssds_[i] = 0; } - - void EDS::calc_covar_step_size() { - //calulcate step size - //uses scale here, which by default is center - double tmp; - for(unsigned int i = 0; i< ncvs_; ++i){ - tmp = 0; + if(b_covar_) + for(unsigned int i = 0; i < ncvs_; ++i) for(unsigned int j = 0; j < ncvs_; ++j) - tmp += difference(i, means_[i], center_[i]) * covar_(i,j); - step_size_[i] = 2 * tmp / kbt_ / scale_[i] * update_calls_ / (update_calls_ - 1); - } - + covar_(i,j) = 0; +} + +void EDS::calc_covar_step_size() { + //calulcate step size + //uses scale here, which by default is center + double tmp; + for(unsigned int i = 0; i< ncvs_; ++i) { + tmp = 0; + for(unsigned int j = 0; j < ncvs_; ++j) + tmp += difference(i, means_[i], center_[i]) * covar_(i,j); + step_size_[i] = 2 * tmp / kbt_ / scale_[i] * update_calls_ / (update_calls_ - 1); } - void EDS::calc_ssd_step_size() { - double tmp; - for(unsigned int i = 0; i< ncvs_; ++i){ - tmp = 2. * difference(i, means_[i], center_[i]) * ssds_[i] / (update_calls_ - 1); - step_size_[i] = tmp / kbt_/scale_[i]; - } +} + +void EDS::calc_ssd_step_size() { + double tmp; + for(unsigned int i = 0; i< ncvs_; ++i) { + tmp = 2. * difference(i, means_[i], center_[i]) * ssds_[i] / (update_calls_ - 1); + step_size_[i] = tmp / kbt_/scale_[i]; } +} - void EDS::update_bias() - { - if(b_covar_) - calc_covar_step_size(); - else - calc_ssd_step_size(); - - for(unsigned int i = 0; i< ncvs_; ++i){ - - //check if the step_size exceeds maximum possible gradient - step_size_[i] = copysign(fmin(fabs(step_size_[i]), max_coupling_grad_[i]), step_size_[i]); - - //reset means/vars - reset_statistics(); - - //multidimesional stochastic step - if(ncvs_ == 1 || (rand_.RandU01() < (multi_prop_) ) ) { - coupling_accum_[i] += step_size_[i] * step_size_[i]; - - //equation 5 in White and Voth, JCTC 2014 - //no negative sign because it's in step_size - set_coupling_[i] += max_coupling_range_[i]/sqrt(coupling_accum_[i])*step_size_[i]; - coupling_rate_[i] = (set_coupling_[i]-current_coupling_[i])/update_period_; - - } else { - //do not change the bias - coupling_rate_[i] = 0; - } +void EDS::update_bias() +{ + if(b_covar_) + calc_covar_step_size(); + else + calc_ssd_step_size(); + + for(unsigned int i = 0; i< ncvs_; ++i) { + + //check if the step_size exceeds maximum possible gradient + step_size_[i] = copysign(fmin(fabs(step_size_[i]), max_coupling_grad_[i]), step_size_[i]); + + //reset means/vars + reset_statistics(); + + //multidimesional stochastic step + if(ncvs_ == 1 || (rand_.RandU01() < (multi_prop_) ) ) { + coupling_accum_[i] += step_size_[i] * step_size_[i]; + + //equation 5 in White and Voth, JCTC 2014 + //no negative sign because it's in step_size + set_coupling_[i] += max_coupling_range_[i]/sqrt(coupling_accum_[i])*step_size_[i]; + coupling_rate_[i] = (set_coupling_[i]-current_coupling_[i])/update_period_; + + } else { + //do not change the bias + coupling_rate_[i] = 0; } } +} - void EDS::update(){ - //pass - } +void EDS::update() { + //pass +} - EDS::~EDS(){ - out_restart_.close(); - } +EDS::~EDS() { + out_restart_.close(); +} - void EDS::turnOnDerivatives(){ - // do nothing - // this is to avoid errors triggered when a bias is used as a CV - // (This is done in ExtendedLagrangian.cpp) - } +void EDS::turnOnDerivatives() { + // do nothing + // this is to avoid errors triggered when a bias is used as a CV + // (This is done in ExtendedLagrangian.cpp) +} -}}//close the 2 namespaces +} +}//close the 2 namespaces diff --git a/src/function/Combine.cpp b/src/function/Combine.cpp index 5e3ac9b29..e76ed7b8b 100644 --- a/src/function/Combine.cpp +++ b/src/function/Combine.cpp @@ -26,8 +26,8 @@ using namespace std; -namespace PLMD{ -namespace function{ +namespace PLMD { +namespace function { //+PLUMEDOC FUNCTION COMBINE /* @@ -92,7 +92,7 @@ public: PLUMED_REGISTER_ACTION(Combine,"COMBINE") -void Combine::registerKeywords(Keywords& keys){ +void Combine::registerKeywords(Keywords& keys) { Function::registerKeywords(keys); keys.use("ARG"); keys.use("PERIODIC"); keys.add("compulsory","COEFFICIENTS","1.0","the coefficients of the arguments in your function"); @@ -102,12 +102,12 @@ void Combine::registerKeywords(Keywords& keys){ } Combine::Combine(const ActionOptions&ao): -Action(ao), -Function(ao), -normalize(false), -coefficients(getNumberOfArguments(),1.0), -parameters(getNumberOfArguments(),0.0), -powers(getNumberOfArguments(),1.0) + Action(ao), + Function(ao), + normalize(false), + coefficients(getNumberOfArguments(),1.0), + parameters(getNumberOfArguments(),0.0), + powers(getNumberOfArguments(),1.0) { parseVector("COEFFICIENTS",coefficients); if(coefficients.size()!=static_cast<unsigned>(getNumberOfArguments())) @@ -123,29 +123,29 @@ powers(getNumberOfArguments(),1.0) parseFlag("NORMALIZE",normalize); - if(normalize){ + if(normalize) { double n=0.0; - for(unsigned i=0;i<coefficients.size();i++) n+=coefficients[i]; - for(unsigned i=0;i<coefficients.size();i++) coefficients[i]*=(1.0/n); + for(unsigned i=0; i<coefficients.size(); i++) n+=coefficients[i]; + for(unsigned i=0; i<coefficients.size(); i++) coefficients[i]*=(1.0/n); } - - addValueWithDerivatives(); + + addValueWithDerivatives(); checkRead(); log.printf(" with coefficients:"); - for(unsigned i=0;i<coefficients.size();i++) log.printf(" %f",coefficients[i]); + for(unsigned i=0; i<coefficients.size(); i++) log.printf(" %f",coefficients[i]); log.printf("\n"); log.printf(" with parameters:"); - for(unsigned i=0;i<parameters.size();i++) log.printf(" %f",parameters[i]); + for(unsigned i=0; i<parameters.size(); i++) log.printf(" %f",parameters[i]); log.printf("\n"); log.printf(" and powers:"); - for(unsigned i=0;i<powers.size();i++) log.printf(" %f",powers[i]); + for(unsigned i=0; i<powers.size(); i++) log.printf(" %f",powers[i]); log.printf("\n"); } -void Combine::calculate(){ +void Combine::calculate() { double combine=0.0; - for(unsigned i=0;i<coefficients.size();++i){ + for(unsigned i=0; i<coefficients.size(); ++i) { double cv = (getArgument(i)-parameters[i]); combine+=coefficients[i]*pow(cv,powers[i]); setDerivative(i,coefficients[i]*powers[i]*pow(cv,powers[i]-1.0)); diff --git a/src/function/Ensemble.cpp b/src/function/Ensemble.cpp index 329b59517..9976c2501 100644 --- a/src/function/Ensemble.cpp +++ b/src/function/Ensemble.cpp @@ -26,20 +26,20 @@ using namespace std; -namespace PLMD{ -namespace function{ +namespace PLMD { +namespace function { //+PLUMEDOC FUNCTION ENSEMBLE /* Calculates the replica averaging of a collective variable over multiple replicas. -Each collective variable is averaged separately and stored in a component labelled <em>label</em>.cvlabel. +Each collective variable is averaged separately and stored in a component labelled <em>label</em>.cvlabel. \par Examples The following input tells plumed to calculate the distance between atoms 3 and 5 and the average it over the available replicas. \verbatim -dist: DISTANCE ATOMS=3,5 +dist: DISTANCE ATOMS=3,5 ens: ENSEMBLE ARG=dist PRINT ARG=dist,ens.dist \endverbatim @@ -72,11 +72,11 @@ public: PLUMED_REGISTER_ACTION(Ensemble,"ENSEMBLE") -void Ensemble::registerKeywords(Keywords& keys){ +void Ensemble::registerKeywords(Keywords& keys) { Function::registerKeywords(keys); keys.use("ARG"); - keys.addFlag("REWEIGHT",false,"simple REWEIGHT using the latest ARG as energy"); - keys.addFlag("CENTRAL",false,"calculate a central moment instead of a standard moment"); + keys.addFlag("REWEIGHT",false,"simple REWEIGHT using the latest ARG as energy"); + keys.addFlag("CENTRAL",false,"calculate a central moment instead of a standard moment"); keys.add("optional","TEMP","the system temperature - this is only needed if you are reweighting"); keys.add("optional","MOMENT","the moment you want to calculate in alternative to the mean or the variance"); keys.add("optional","POWER","the power of the mean (and moment)"); @@ -84,17 +84,17 @@ void Ensemble::registerKeywords(Keywords& keys){ } Ensemble::Ensemble(const ActionOptions&ao): -Action(ao), -Function(ao), -do_reweight(false), -do_moments(false), -do_central(false), -do_powers(false), -kbt(-1.0), -moment(0), -power(0) + Action(ao), + Function(ao), + do_reweight(false), + do_moments(false), + do_central(false), + do_powers(false), + kbt(-1.0), + moment(0), + power(0) { - parseFlag("REWEIGHT", do_reweight); + parseFlag("REWEIGHT", do_reweight); double temp=0.0; parse("TEMP",temp); if(do_reweight) { @@ -108,7 +108,7 @@ power(0) if(moment!=0) do_moments=true; parseFlag("CENTRAL", do_central); if(!do_moments&&do_central) error("To calculate a CENTRAL moment you need to define for which MOMENT"); - + parse("POWER",power); if(power==1) error("POWER can be any number but for 0 and 1"); if(power!=0) do_powers=true; @@ -116,7 +116,7 @@ power(0) checkRead(); master = (comm.Get_rank()==0); - ens_dim=0; + ens_dim=0; my_repl=0; if(master) { ens_dim=multi_sim_comm.Get_size(); @@ -125,22 +125,22 @@ power(0) comm.Bcast(ens_dim,0); comm.Bcast(my_repl,0); if(ens_dim<2) log.printf("WARNING: ENSEMBLE with one replica is not doing any averaging!\n"); - + // prepare output components, the number depending on reweighing or not narg = getNumberOfArguments(); if(do_reweight) narg--; - + // these are the averages - for(unsigned i=0;i<narg;i++) { - std::string s=getPntrToArgument(i)->getName(); - addComponentWithDerivatives(s); - getPntrToComponent(i)->setNotPeriodic(); + for(unsigned i=0; i<narg; i++) { + std::string s=getPntrToArgument(i)->getName(); + addComponentWithDerivatives(s); + getPntrToComponent(i)->setNotPeriodic(); } - // these are the moments + // these are the moments if(do_moments) { - for(unsigned i=0;i<narg;i++) { + for(unsigned i=0; i<narg; i++) { std::string s=getPntrToArgument(i)->getName()+"_m"; - addComponentWithDerivatives(s); + addComponentWithDerivatives(s); getPntrToComponent(i+narg)->setNotPeriodic(); } } @@ -152,38 +152,38 @@ power(0) if(do_powers) log.printf(" calculating the %lf power of the mean (and moment)\n", power); } -void Ensemble::calculate(){ +void Ensemble::calculate() { double norm = 0.0; double fact = 0.0; - // calculate the weights either from BIAS - if(do_reweight){ + // calculate the weights either from BIAS + if(do_reweight) { vector<double> bias; bias.resize(ens_dim); - if(master){ - bias[my_repl] = getArgument(narg); - if(ens_dim>1) multi_sim_comm.Sum(&bias[0], ens_dim); + if(master) { + bias[my_repl] = getArgument(narg); + if(ens_dim>1) multi_sim_comm.Sum(&bias[0], ens_dim); } comm.Sum(&bias[0], ens_dim); const double maxbias = *(std::max_element(bias.begin(), bias.end())); - for(unsigned i=0; i<ens_dim; ++i){ - bias[i] = exp((bias[i]-maxbias)/kbt); + for(unsigned i=0; i<ens_dim; ++i) { + bias[i] = exp((bias[i]-maxbias)/kbt); norm += bias[i]; } fact = bias[my_repl]/norm; - // or arithmetic ones + // or arithmetic ones } else { - norm = static_cast<double>(ens_dim); - fact = 1.0/norm; + norm = static_cast<double>(ens_dim); + fact = 1.0/norm; } const double fact_kbt = fact/kbt; vector<double> mean(narg); vector<double> dmean(narg,fact); - // calculate the mean + // calculate the mean if(master) { - for(unsigned i=0;i<narg;++i) mean[i] = fact*getArgument(i); + for(unsigned i=0; i<narg; ++i) mean[i] = fact*getArgument(i); if(ens_dim>1) multi_sim_comm.Sum(&mean[0], narg); } comm.Sum(&mean[0], narg); @@ -196,29 +196,29 @@ void Ensemble::calculate(){ // standard moment if(!do_central) { if(master) { - for(unsigned i=0;i<narg;++i) { + for(unsigned i=0; i<narg; ++i) { const double tmp = fact*pow(getArgument(i),moment-1); v_moment[i] = tmp*getArgument(i); dv_moment[i] = moment*tmp; } if(ens_dim>1) multi_sim_comm.Sum(&v_moment[0], narg); } else { - for(unsigned i=0;i<narg;++i) { + for(unsigned i=0; i<narg; ++i) { const double tmp = fact*pow(getArgument(i),moment-1); dv_moment[i] = moment*tmp; } } - // central moment + // central moment } else { if(master) { - for(unsigned i=0;i<narg;++i) { + for(unsigned i=0; i<narg; ++i) { const double tmp = pow(getArgument(i)-mean[i],moment-1); v_moment[i] = fact*tmp*(getArgument(i)-mean[i]); dv_moment[i] = moment*tmp*(fact-fact/norm); } if(ens_dim>1) multi_sim_comm.Sum(&v_moment[0], narg); } else { - for(unsigned i=0;i<narg;++i) { + for(unsigned i=0; i<narg; ++i) { const double tmp = pow(getArgument(i)-mean[i],moment-1); dv_moment[i] = moment*tmp*(fact-fact/norm); } @@ -229,20 +229,20 @@ void Ensemble::calculate(){ // calculate powers of moments if(do_powers) { - for(unsigned i=0;i<narg;++i) { + for(unsigned i=0; i<narg; ++i) { const double tmp1 = pow(mean[i],power-1); mean[i] *= tmp1; dmean[i] *= power*tmp1; - if(do_moments) { + if(do_moments) { const double tmp2 = pow(v_moment[i],power-1); v_moment[i] *= tmp2; - dv_moment[i] *= power*tmp2; + dv_moment[i] *= power*tmp2; } } } - + // set components - for(unsigned i=0;i<narg;++i){ + for(unsigned i=0; i<narg; ++i) { // set mean Value* v=getPntrToComponent(i); v->set(mean[i]); @@ -261,7 +261,7 @@ void Ensemble::calculate(){ setDerivative(u, narg, w_tmp); } } - } + } } } diff --git a/src/function/FuncPathMSD.cpp b/src/function/FuncPathMSD.cpp index 5aa68d120..f4d481d73 100644 --- a/src/function/FuncPathMSD.cpp +++ b/src/function/FuncPathMSD.cpp @@ -30,30 +30,30 @@ using namespace std; -namespace PLMD{ -namespace function{ +namespace PLMD { +namespace function { //+PLUMEDOC FUNCTION FUNCPATHMSD /* -This function calculates path collective variables. +This function calculates path collective variables. -This is the Path Collective Variables implementation +This is the Path Collective Variables implementation ( see \cite brand07 ). -This variable computes the progress along a given set of frames that is provided -in input ("s" component) and the distance from them ("z" component). -It is a function of MSD that are obtained by the joint use of MSD variable and SQUARED flag +This variable computes the progress along a given set of frames that is provided +in input ("s" component) and the distance from them ("z" component). +It is a function of MSD that are obtained by the joint use of MSD variable and SQUARED flag (see below). \par Examples -Here below is a case where you have defined three frames and you want to +Here below is a case where you have defined three frames and you want to calculate the progress alng the path and the distance from it in p1 \verbatim t1: RMSD REFERENCE=frame_1.dat TYPE=OPTIMAL SQUARED t2: RMSD REFERENCE=frame_21.dat TYPE=OPTIMAL SQUARED t3: RMSD REFERENCE=frame_42.dat TYPE=OPTIMAL SQUARED -p1: FUNCPATHMSD ARG=t1,t2,t3 LAMBDA=500.0 +p1: FUNCPATHMSD ARG=t1,t2,t3 LAMBDA=500.0 PRINT ARG=t1,t2,t3,p1.s,p1.z STRIDE=1 FILE=colvar FMT=%8.4f \endverbatim @@ -61,83 +61,83 @@ In this second example is shown how to define a PATH in the \ref CONTACTMAP spac \verbatim CONTACTMAP ... -ATOMS1=1,2 REFERENCE1=0.1 -ATOMS2=3,4 REFERENCE2=0.5 -ATOMS3=4,5 REFERENCE3=0.25 -ATOMS4=5,6 REFERENCE4=0.0 -SWITCH=(RATIONAL R_0=1.5) +ATOMS1=1,2 REFERENCE1=0.1 +ATOMS2=3,4 REFERENCE2=0.5 +ATOMS3=4,5 REFERENCE3=0.25 +ATOMS4=5,6 REFERENCE4=0.0 +SWITCH=(RATIONAL R_0=1.5) LABEL=c1 CMDIST ... CONTACTMAP CONTACTMAP ... -ATOMS1=1,2 REFERENCE1=0.3 -ATOMS2=3,4 REFERENCE2=0.9 -ATOMS3=4,5 REFERENCE3=0.45 -ATOMS4=5,6 REFERENCE4=0.1 -SWITCH=(RATIONAL R_0=1.5) +ATOMS1=1,2 REFERENCE1=0.3 +ATOMS2=3,4 REFERENCE2=0.9 +ATOMS3=4,5 REFERENCE3=0.45 +ATOMS4=5,6 REFERENCE4=0.1 +SWITCH=(RATIONAL R_0=1.5) LABEL=c2 CMDIST ... CONTACTMAP CONTACTMAP ... -ATOMS1=1,2 REFERENCE1=1.0 -ATOMS2=3,4 REFERENCE2=1.0 -ATOMS3=4,5 REFERENCE3=1.0 -ATOMS4=5,6 REFERENCE4=1.0 -SWITCH=(RATIONAL R_0=1.5) +ATOMS1=1,2 REFERENCE1=1.0 +ATOMS2=3,4 REFERENCE2=1.0 +ATOMS3=4,5 REFERENCE3=1.0 +ATOMS4=5,6 REFERENCE4=1.0 +SWITCH=(RATIONAL R_0=1.5) LABEL=c3 CMDIST ... CONTACTMAP -p1: FUNCPATHMSD ARG=c1,c2,c3 LAMBDA=500.0 +p1: FUNCPATHMSD ARG=c1,c2,c3 LAMBDA=500.0 PRINT ARG=c1,c2,c3,p1.s,p1.z STRIDE=1 FILE=colvar FMT=%8.4f \endverbatim */ //+ENDPLUMEDOC - + class FuncPathMSD : public Function { double lambda; int neigh_size; double neigh_stride; vector< pair<Value *,double> > neighpair; map<Value *,double > indexmap; // use double to allow isomaps - vector <Value*> allArguments; + vector <Value*> allArguments; // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -// this below is useful when one wants to sort a vector of double and have back the order +// this below is useful when one wants to sort a vector of double and have back the order // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // create a custom sorter -typedef vector<double>::const_iterator myiter; -struct ordering { - bool operator ()(pair<unsigned , myiter> const& a, pair<unsigned , myiter> const& b) { - return *(a.second) < *(b.second); - } -}; + typedef vector<double>::const_iterator myiter; + struct ordering { + bool operator ()(pair<unsigned, myiter> const& a, pair<unsigned, myiter> const& b) { + return *(a.second) < *(b.second); + } + }; // sorting utility -vector<int> increasingOrder( vector<double> &v){ - // make a pair - vector< pair<unsigned , myiter> > order(v.size()); - unsigned n = 0; - for (myiter it = v.begin(); it != v.end(); ++it, ++n){ - order[n] = make_pair(n, it); // note: heere i do not put the values but the addresses that point to the value - } - // now sort according the second value - sort(order.begin(), order.end(), ordering()); - vector<int> vv(v.size());n=0; - for (const auto & it : order){ - vv[n]=it.first;n++; - } - return vv; -} + vector<int> increasingOrder( vector<double> &v) { + // make a pair + vector< pair<unsigned, myiter> > order(v.size()); + unsigned n = 0; + for (myiter it = v.begin(); it != v.end(); ++it, ++n) { + order[n] = make_pair(n, it); // note: heere i do not put the values but the addresses that point to the value + } + // now sort according the second value + sort(order.begin(), order.end(), ordering()); + vector<int> vv(v.size()); n=0; + for (const auto & it : order) { + vv[n]=it.first; n++; + } + return vv; + } // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -struct pairordering { - bool operator ()(pair<Value * , double> const& a, pair<Value* , double> const& b) { - return (a).second > (b).second; - } -}; + struct pairordering { + bool operator ()(pair<Value *, double> const& a, pair<Value*, double> const& b) { + return (a).second > (b).second; + } + }; public: explicit FuncPathMSD(const ActionOptions&); @@ -149,7 +149,7 @@ public: PLUMED_REGISTER_ACTION(FuncPathMSD,"FUNCPATHMSD") -void FuncPathMSD::registerKeywords(Keywords& keys){ +void FuncPathMSD::registerKeywords(Keywords& keys) { Function::registerKeywords(keys); keys.use("ARG"); keys.add("compulsory","LAMBDA","the lambda parameter is needed for smoothing, is in the units of plumed"); @@ -160,10 +160,10 @@ void FuncPathMSD::registerKeywords(Keywords& keys){ keys.addOutputComponent("z","default","the distance from the path"); } FuncPathMSD::FuncPathMSD(const ActionOptions&ao): -Action(ao), -Function(ao), -neigh_size(-1), -neigh_stride(-1.) + Action(ao), + Function(ao), + neigh_size(-1), + neigh_stride(-1.) { parse("LAMBDA",lambda); @@ -171,52 +171,52 @@ neigh_stride(-1.) parse("NEIGH_STRIDE",neigh_stride); checkRead(); log.printf(" lambda is %f\n",lambda); - // list the action involved and check the type + // list the action involved and check the type std::string myname=getPntrToArgument(0)->getPntrToAction()->getName(); if(myname!="RMSD"&&myname!="CONTACTMAP"&&myname!="DISTANCE") error("One or more of your arguments is not of RMSD/CONTACTMAP/DISTANCE type!!!"); - for(unsigned i=1;i<getNumberOfArguments();i++){ - // for each value get the name and the label of the corresponding action - if( getPntrToArgument(i)->getPntrToAction()->getName()!=myname ) error("mismatch between the types of arguments"); - } - log.printf(" Consistency check completed! Your path cvs look good!\n"); + for(unsigned i=1; i<getNumberOfArguments(); i++) { + // for each value get the name and the label of the corresponding action + if( getPntrToArgument(i)->getPntrToAction()->getName()!=myname ) error("mismatch between the types of arguments"); + } + log.printf(" Consistency check completed! Your path cvs look good!\n"); // do some neighbor printout - if(neigh_stride>0. || neigh_size>0){ - if(neigh_size>getNumberOfArguments()){ - log.printf(" List size required ( %d ) is too large: resizing to the maximum number of arg required: %d \n",neigh_size,getNumberOfArguments()); - neigh_size=getNumberOfArguments(); - } - log.printf(" Neighbor list enabled: \n"); - log.printf(" size : %d elements\n",neigh_size); - log.printf(" stride : %f time \n",neigh_stride); - }else{ - log.printf(" Neighbor list NOT enabled \n"); + if(neigh_stride>0. || neigh_size>0) { + if(neigh_size>getNumberOfArguments()) { + log.printf(" List size required ( %d ) is too large: resizing to the maximum number of arg required: %d \n",neigh_size,getNumberOfArguments()); + neigh_size=getNumberOfArguments(); + } + log.printf(" Neighbor list enabled: \n"); + log.printf(" size : %d elements\n",neigh_size); + log.printf(" stride : %f time \n",neigh_stride); + } else { + log.printf(" Neighbor list NOT enabled \n"); } addComponentWithDerivatives("s"); componentIsNotPeriodic("s"); addComponentWithDerivatives("z"); componentIsNotPeriodic("z"); - // now backup the arguments - for(unsigned i=0;i<getNumberOfArguments();i++)allArguments.push_back(getPntrToArgument(i)); + // now backup the arguments + for(unsigned i=0; i<getNumberOfArguments(); i++)allArguments.push_back(getPntrToArgument(i)); double i=1.; - for(const auto & it : allArguments){ - indexmap[it]=i;i+=1.; + for(const auto & it : allArguments) { + indexmap[it]=i; i+=1.; } - + } // calculator -void FuncPathMSD::calculate(){ - // log.printf("NOW CALCULATE! \n"); +void FuncPathMSD::calculate() { +// log.printf("NOW CALCULATE! \n"); double s_path=0.; double partition=0.; - if(neighpair.empty()){ // at first step, resize it - neighpair.resize(allArguments.size()); - for(unsigned i=0;i<allArguments.size();i++)neighpair[i].first=allArguments[i]; + if(neighpair.empty()) { // at first step, resize it + neighpair.resize(allArguments.size()); + for(unsigned i=0; i<allArguments.size(); i++)neighpair[i].first=allArguments[i]; } Value* val_s_path=getPntrToComponent("s"); Value* val_z_path=getPntrToComponent("z"); - for(auto & it : neighpair){ + for(auto & it : neighpair) { it.second=exp(-lambda*(it.first->get())); s_path+=(indexmap[it.first])*it.second; partition+=it.second; @@ -225,7 +225,7 @@ void FuncPathMSD::calculate(){ val_s_path->set(s_path); val_z_path->set(-(1./lambda)*std::log(partition)); int n=0; - for(const auto & it : neighpair){ + for(const auto & it : neighpair) { double expval=it.second; double tmp=lambda*expval*(s_path-(indexmap[it.first]))/partition; setDerivative(val_s_path,n,tmp); @@ -238,60 +238,60 @@ void FuncPathMSD::calculate(){ /// /// this function updates the needed argument list /// -void FuncPathMSD::prepare(){ +void FuncPathMSD::prepare() { - // neighbor list: rank and activate the chain for the next step + // neighbor list: rank and activate the chain for the next step // neighbor list: if neigh_size<0 never sort and keep the full vector - // neighbor list: if neigh_size>0 - // if the size is full -> sort the vector and decide the dependencies for next step - // if the size is not full -> check if next step will need the full dependency otherwise keep this dependencies + // neighbor list: if neigh_size>0 + // if the size is full -> sort the vector and decide the dependencies for next step + // if the size is not full -> check if next step will need the full dependency otherwise keep this dependencies // here just resize the neighpair. The real resizing of reinit will be done by the prepare stage that will modify the list of arguments - if (neigh_size>0){ - if(neighpair.size()==allArguments.size()){ // I just did the complete round: need to sort, shorten and give it a go - // sort the values - sort(neighpair.begin(),neighpair.end(),pairordering()); - // resize the effective list - neighpair.resize(neigh_size); - log.printf(" NEIGH LIST NOW INCLUDE INDEXES: "); - for(int i=0;i<neigh_size;++i)log.printf(" %f ",indexmap[neighpair[i].first]);log.printf(" \n"); - }else{ - if( int(getStep())%int(neigh_stride/getTimeStep())==0 ){ - log.printf(" Time %f : recalculating full neighlist \n",getStep()*getTimeStep()); - neighpair.resize(allArguments.size()); - for(unsigned i=0;i<allArguments.size();i++)neighpair[i].first=allArguments[i]; - } - } - }else{ - if( int(getStep())==0){ - neighpair.resize(allArguments.size()); - for(unsigned i=0;i<allArguments.size();i++)neighpair[i].first=allArguments[i]; - } + if (neigh_size>0) { + if(neighpair.size()==allArguments.size()) { // I just did the complete round: need to sort, shorten and give it a go + // sort the values + sort(neighpair.begin(),neighpair.end(),pairordering()); + // resize the effective list + neighpair.resize(neigh_size); + log.printf(" NEIGH LIST NOW INCLUDE INDEXES: "); + for(int i=0; i<neigh_size; ++i)log.printf(" %f ",indexmap[neighpair[i].first]); log.printf(" \n"); + } else { + if( int(getStep())%int(neigh_stride/getTimeStep())==0 ) { + log.printf(" Time %f : recalculating full neighlist \n",getStep()*getTimeStep()); + neighpair.resize(allArguments.size()); + for(unsigned i=0; i<allArguments.size(); i++)neighpair[i].first=allArguments[i]; + } + } + } else { + if( int(getStep())==0) { + neighpair.resize(allArguments.size()); + for(unsigned i=0; i<allArguments.size(); i++)neighpair[i].first=allArguments[i]; + } } - vector<Value*> argstocall; - //log.printf("PREPARING \n"); - argstocall.clear(); - if(!neighpair.empty()){ - for(const auto & it : neighpair){ - argstocall.push_back( it.first ); - // log.printf("CALLING %p %f ",(*it).first ,indexmap[(*it).first] ); + vector<Value*> argstocall; +//log.printf("PREPARING \n"); + argstocall.clear(); + if(!neighpair.empty()) { + for(const auto & it : neighpair) { + argstocall.push_back( it.first ); + // log.printf("CALLING %p %f ",(*it).first ,indexmap[(*it).first] ); } - }else{ - for(unsigned i=0;i<allArguments.size();i++){ - argstocall.push_back(allArguments[i]); + } else { + for(unsigned i=0; i<allArguments.size(); i++) { + argstocall.push_back(allArguments[i]); } - } - // now the list of argument changes - requestArguments(argstocall); - //now resize the derivatives as well - //for each value in this action - for(int i=0;i< getNumberOfComponents();i++){ - //resize the derivative to the number the - getPntrToComponent(i)->clearDerivatives(); - getPntrToComponent(i)->resizeDerivatives(getNumberOfArguments()); - } - //log.printf("PREPARING DONE! \n"); + } +// now the list of argument changes + requestArguments(argstocall); +//now resize the derivatives as well +//for each value in this action + for(int i=0; i< getNumberOfComponents(); i++) { + //resize the derivative to the number the + getPntrToComponent(i)->clearDerivatives(); + getPntrToComponent(i)->resizeDerivatives(getNumberOfArguments()); + } +//log.printf("PREPARING DONE! \n"); } } diff --git a/src/function/FuncSumHills.cpp b/src/function/FuncSumHills.cpp index 5231b0fdc..65049b9b6 100644 --- a/src/function/FuncSumHills.cpp +++ b/src/function/FuncSumHills.cpp @@ -31,18 +31,18 @@ using namespace std; -namespace PLMD{ -namespace function{ +namespace PLMD { +namespace function { -//+PLUMEDOC FUNCTION FUNCSUMHILLS +//+PLUMEDOC FUNCTION FUNCSUMHILLS /* This function is intended to be called by the command line tool sum_hills -and it is meant to integrate a HILLS file or an HILLS file interpreted as -a histogram i a variety of ways. Therefore it is not expected that you use this +and it is meant to integrate a HILLS file or an HILLS file interpreted as +a histogram i a variety of ways. Therefore it is not expected that you use this during your dynamics (it will crash!) -In the future one could implement periodic integration during the metadynamics +In the future one could implement periodic integration during the metadynamics or straightforward MD as a tool to check convergence \par Examples @@ -52,130 +52,131 @@ There are currently no examples for this keyword. */ //+ENDPLUMEDOC -class FilesHandler{ - vector <string> filenames; - vector <IFile*> ifiles; - Action *action; - Log *log; - bool parallelread; - unsigned beingread; - bool isopen; - public: - FilesHandler(const vector<string> &filenames, const bool ¶llelread , Action &myaction , Log &mylog); - bool readBunch(BiasRepresentation *br, int stride); - bool scanOneHill(BiasRepresentation *br, IFile *ifile ); - void getMinMaxBin(vector<Value*> vals, Communicator &cc, vector<double> &vmin, vector<double> &vmax, vector<unsigned> &vbin); - void getMinMaxBin(vector<Value*> vals, Communicator &cc, vector<double> &vmin, vector<double> &vmax, vector<unsigned> &vbin, vector<double> &histosigma); - ~FilesHandler(); +class FilesHandler { + vector <string> filenames; + vector <IFile*> ifiles; + Action *action; + Log *log; + bool parallelread; + unsigned beingread; + bool isopen; +public: + FilesHandler(const vector<string> &filenames, const bool ¶llelread, Action &myaction, Log &mylog); + bool readBunch(BiasRepresentation *br, int stride); + bool scanOneHill(BiasRepresentation *br, IFile *ifile ); + void getMinMaxBin(vector<Value*> vals, Communicator &cc, vector<double> &vmin, vector<double> &vmax, vector<unsigned> &vbin); + void getMinMaxBin(vector<Value*> vals, Communicator &cc, vector<double> &vmin, vector<double> &vmax, vector<unsigned> &vbin, vector<double> &histosigma); + ~FilesHandler(); }; -FilesHandler::FilesHandler(const vector<string> &filenames, const bool ¶llelread , Action &action , Log &mylog ):filenames(filenames),log(&mylog),parallelread(parallelread),beingread(0),isopen(false){ - this->action=&action; - for(unsigned i=0;i<filenames.size();i++){ - IFile *ifile = new IFile(); - ifile->link(action); - ifiles.push_back(ifile); - plumed_massert((ifile->FileExist(filenames[i])), "the file "+filenames[i]+" does not exist " ); - } - +FilesHandler::FilesHandler(const vector<string> &filenames, const bool ¶llelread, Action &action, Log &mylog ):filenames(filenames),log(&mylog),parallelread(parallelread),beingread(0),isopen(false) { + this->action=&action; + for(unsigned i=0; i<filenames.size(); i++) { + IFile *ifile = new IFile(); + ifile->link(action); + ifiles.push_back(ifile); + plumed_massert((ifile->FileExist(filenames[i])), "the file "+filenames[i]+" does not exist " ); + } + } -FilesHandler::~FilesHandler(){ - for(unsigned i=0;i<ifiles.size();i++) delete ifiles[i]; +FilesHandler::~FilesHandler() { + for(unsigned i=0; i<ifiles.size(); i++) delete ifiles[i]; } -// note that the FileHandler is completely transparent respect to the biasrepresentation +// note that the FileHandler is completely transparent respect to the biasrepresentation // no check are made at this level -bool FilesHandler::readBunch(BiasRepresentation *br , int stride = -1){ - bool morefiles; morefiles=true; - if(parallelread){ - (*log)<<" doing parallelread \n"; - plumed_merror("parallelread is not yet implemented !!!"); - }else{ - (*log)<<" doing serialread \n"; - // read one by one hills - // is the type defined? if not, assume it is a gaussian - IFile *ff; - ff=ifiles[beingread]; - if(!isopen){ - (*log)<<" opening file "<<filenames[beingread]<<"\n"; - ff->open(filenames[beingread]);isopen=true; - } - int n; - while(true){ - bool fileisover=true; - while(scanOneHill(br,ff)){ - // here do the dump if needed - n=br->getNumberOfKernels(); - if(stride>0 && n%stride==0 && n!=0 ){ - (*log)<<" done with this chunk: now with "<<n<<" kernels \n"; - fileisover=false; - break; - } - } - if(fileisover){ - (*log)<<" closing file "<<filenames[beingread]<<"\n"; - ff->close(); - isopen=false; - (*log)<<" now total "<<br->getNumberOfKernels()<<" kernels \n"; - beingread++; - if(beingread<ifiles.size()){ - ff=ifiles[beingread];ff->open(filenames[beingread]); - (*log)<<" opening file "<<filenames[beingread]<<"\n"; - isopen=true; - }else{morefiles=false; - (*log)<<" final chunk: now with "<<n<<" kernels \n"; - break; - } - } - // if there are no more files to read and this file is over then quit - if(fileisover && !morefiles){break;} - // if you are in the middle of a file and you are here - // then means that you read what you need to read - if(!fileisover ){break;} - } - } - return morefiles; +bool FilesHandler::readBunch(BiasRepresentation *br, int stride = -1) { + bool morefiles; morefiles=true; + if(parallelread) { + (*log)<<" doing parallelread \n"; + plumed_merror("parallelread is not yet implemented !!!"); + } else { + (*log)<<" doing serialread \n"; + // read one by one hills + // is the type defined? if not, assume it is a gaussian + IFile *ff; + ff=ifiles[beingread]; + if(!isopen) { + (*log)<<" opening file "<<filenames[beingread]<<"\n"; + ff->open(filenames[beingread]); isopen=true; + } + int n; + while(true) { + bool fileisover=true; + while(scanOneHill(br,ff)) { + // here do the dump if needed + n=br->getNumberOfKernels(); + if(stride>0 && n%stride==0 && n!=0 ) { + (*log)<<" done with this chunk: now with "<<n<<" kernels \n"; + fileisover=false; + break; + } + } + if(fileisover) { + (*log)<<" closing file "<<filenames[beingread]<<"\n"; + ff->close(); + isopen=false; + (*log)<<" now total "<<br->getNumberOfKernels()<<" kernels \n"; + beingread++; + if(beingread<ifiles.size()) { + ff=ifiles[beingread]; ff->open(filenames[beingread]); + (*log)<<" opening file "<<filenames[beingread]<<"\n"; + isopen=true; + } else { + morefiles=false; + (*log)<<" final chunk: now with "<<n<<" kernels \n"; + break; + } + } + // if there are no more files to read and this file is over then quit + if(fileisover && !morefiles) {break;} + // if you are in the middle of a file and you are here + // then means that you read what you need to read + if(!fileisover ) {break;} + } + } + return morefiles; } -void FilesHandler::getMinMaxBin(vector<Value*> vals, Communicator &cc, vector<double> &vmin, vector<double> &vmax, vector<unsigned> &vbin){ - // create the representation (no grid) - BiasRepresentation br(vals,cc); - // read all the kernels - readBunch(&br); - // loop over the kernels and get the support - br.getMinMaxBin(vmin,vmax,vbin); +void FilesHandler::getMinMaxBin(vector<Value*> vals, Communicator &cc, vector<double> &vmin, vector<double> &vmax, vector<unsigned> &vbin) { + // create the representation (no grid) + BiasRepresentation br(vals,cc); + // read all the kernels + readBunch(&br); + // loop over the kernels and get the support + br.getMinMaxBin(vmin,vmax,vbin); } -void FilesHandler::getMinMaxBin(vector<Value*> vals, Communicator &cc, vector<double> &vmin, vector<double> &vmax, vector<unsigned> &vbin, vector<double> &histosigma){ - BiasRepresentation br(vals,cc,histosigma); - // read all the kernels - readBunch(&br); - // loop over the kernels and get the support - br.getMinMaxBin(vmin,vmax,vbin); - //for(unsigned i=0;i<vals.size();i++){cerr<<"XXX "<<vmin[i]<<" "<<vmax[i]<<" "<<vbin[i]<<"\n";} +void FilesHandler::getMinMaxBin(vector<Value*> vals, Communicator &cc, vector<double> &vmin, vector<double> &vmax, vector<unsigned> &vbin, vector<double> &histosigma) { + BiasRepresentation br(vals,cc,histosigma); + // read all the kernels + readBunch(&br); + // loop over the kernels and get the support + br.getMinMaxBin(vmin,vmax,vbin); + //for(unsigned i=0;i<vals.size();i++){cerr<<"XXX "<<vmin[i]<<" "<<vmax[i]<<" "<<vbin[i]<<"\n";} } -bool FilesHandler::scanOneHill(BiasRepresentation *br, IFile *ifile ){ - double dummy; - if(ifile->scanField("time",dummy)){ - //(*log)<<" scanning one hill: "<<dummy<<" \n"; - if(ifile->FieldExist("biasf")) ifile->scanField("biasf",dummy); - if(ifile->FieldExist("clock")) ifile->scanField("clock",dummy); - // keep this intermediate function in case you need to parse more data in the future - br->pushKernel(ifile); - //(*log)<<" read hill\n"; - if(br->hasSigmaInInput())ifile->allowIgnoredFields(); - ifile->scanField(); - return true; - }else{ - return false; - } +bool FilesHandler::scanOneHill(BiasRepresentation *br, IFile *ifile ) { + double dummy; + if(ifile->scanField("time",dummy)) { + //(*log)<<" scanning one hill: "<<dummy<<" \n"; + if(ifile->FieldExist("biasf")) ifile->scanField("biasf",dummy); + if(ifile->FieldExist("clock")) ifile->scanField("clock",dummy); + // keep this intermediate function in case you need to parse more data in the future + br->pushKernel(ifile); + //(*log)<<" read hill\n"; + if(br->hasSigmaInInput())ifile->allowIgnoredFields(); + ifile->scanField(); + return true; + } else { + return false; + } } -double mylog( double v1 ){ - return log(v1); +double mylog( double v1 ) { + return log(v1); } -double mylogder( double v1 ){ - return 1./v1; +double mylogder( double v1 ) { + return 1./v1; } @@ -183,8 +184,8 @@ double mylogder( double v1 ){ class FuncSumHills : public Function { - vector<string> hillsFiles,histoFiles; - vector<string> proj; + vector<string> hillsFiles,histoFiles; + vector<string> proj; int initstride; bool iscltool,integratehills,integratehisto,parallelread; bool negativebias; @@ -201,23 +202,23 @@ public: explicit FuncSumHills(const ActionOptions&); ~FuncSumHills(); void calculate(); // this probably is not needed - bool checkFilesAreExisting(const vector<string> & hills ); + bool checkFilesAreExisting(const vector<string> & hills ); static void registerKeywords(Keywords& keys); }; PLUMED_REGISTER_ACTION(FuncSumHills,"FUNCSUMHILLS") -void FuncSumHills::registerKeywords(Keywords& keys){ +void FuncSumHills::registerKeywords(Keywords& keys) { Function::registerKeywords(keys); - keys.use("ARG"); - keys.add("optional","HILLSFILES"," source file for hills creation(may be the same as HILLS)"); // this can be a vector! + keys.use("ARG"); + keys.add("optional","HILLSFILES"," source file for hills creation(may be the same as HILLS)"); // this can be a vector! keys.add("optional","HISTOFILES"," source file for histogram creation(may be the same as HILLS)"); // also this can be a vector! - keys.add("optional","HISTOSIGMA"," sigmas for binning when the histogram correction is needed "); + keys.add("optional","HISTOSIGMA"," sigmas for binning when the histogram correction is needed "); keys.add("optional","PROJ"," only with sumhills: the projection on the cvs"); keys.add("optional","KT"," only with sumhills: the kt factor when projection on cvs"); keys.add("optional","GRID_MIN","the lower bounds for the grid"); keys.add("optional","GRID_MAX","the upper bounds for the grid"); - keys.add("optional","GRID_BIN","the number of bins for the grid"); + keys.add("optional","GRID_BIN","the number of bins for the grid"); keys.add("optional","GRID_SPACING","the approximate grid spacing (to be used as an alternative or together with GRID_BIN)"); keys.add("optional","INTERVAL","set monodimensional INTERVAL"); keys.add("optional","OUTHILLS"," output file for hills "); @@ -233,29 +234,29 @@ void FuncSumHills::registerKeywords(Keywords& keys){ } FuncSumHills::FuncSumHills(const ActionOptions&ao): -Action(ao), -Function(ao), -initstride(-1), -iscltool(false), -integratehills(false), -integratehisto(false), -parallelread(false), -negativebias(false), -nohistory(false), -minTOzero(false), -doInt(false), -lowI_(-1.), -uppI_(-1.), -beta(-1.), -fmt("%14.9f"), -biasrep(NULL), -historep(NULL) + Action(ao), + Function(ao), + initstride(-1), + iscltool(false), + integratehills(false), + integratehisto(false), + parallelread(false), + negativebias(false), + nohistory(false), + minTOzero(false), + doInt(false), + lowI_(-1.), + uppI_(-1.), + beta(-1.), + fmt("%14.9f"), + biasrep(NULL), + historep(NULL) { // format parse("FMT",fmt); - log<<" Output format is "<<fmt<<"\n"; - // here read + log<<" Output format is "<<fmt<<"\n"; + // here read // Grid Stuff vector<std::string> gmin; parseVector("GRID_MIN",gmin); @@ -273,20 +274,20 @@ historep(NULL) parseVector("GRID_SPACING",gspacing); plumed_massert(gspacing.size()==getNumberOfArguments() || gspacing.size()==0,"need GRID_SPACING argument for this") ; if(gspacing.size()!=getNumberOfArguments() && gspacing.size()!=0) error("not enough values for GRID_SPACING"); - if(gspacing.size()!=0 && gbin.size()==0){ + if(gspacing.size()!=0 && gbin.size()==0) { log<<" The number of bins will be estimated from GRID_SPACING\n"; - } else if(gspacing.size()!=0 && gbin.size()!=0){ + } else if(gspacing.size()!=0 && gbin.size()!=0) { log<<" You specified both GRID_BIN and GRID_SPACING\n"; log<<" The more conservative (highest) number of bins will be used for each variable\n"; } - if(gspacing.size()!=0) for(unsigned i=0;i<getNumberOfArguments();i++){ - if(gbin.size()==0) gbin.assign(getNumberOfArguments(),1); - double a,b; - Tools::convert(gmin[i],a); - Tools::convert(gmax[i],b); - unsigned n=((b-a)/gspacing[i])+1; - if(gbin[i]<n) gbin[i]=n; - } + if(gspacing.size()!=0) for(unsigned i=0; i<getNumberOfArguments(); i++) { + if(gbin.size()==0) gbin.assign(getNumberOfArguments(),1); + double a,b; + Tools::convert(gmin[i],a); + Tools::convert(gmax[i],b); + unsigned n=((b-a)/gspacing[i])+1; + if(gbin[i]<n) gbin[i]=n; + } // Inteval keyword vector<double> tmpI(2); @@ -309,31 +310,31 @@ historep(NULL) if(gmax.size()==0) gmax.push_back(strsmax.str()); if(gbin.size()==0) gbin.push_back(200); } - - // hills file: + + // hills file: parseVector("HILLSFILES",hillsFiles); - if(hillsFiles.size()==0){ - integratehills=false; // default behaviour - }else{ - integratehills=true; - for(unsigned i=0;i<hillsFiles.size();i++) log<<" hillsfile : "<<hillsFiles[i]<<"\n"; + if(hillsFiles.size()==0) { + integratehills=false; // default behaviour + } else { + integratehills=true; + for(unsigned i=0; i<hillsFiles.size(); i++) log<<" hillsfile : "<<hillsFiles[i]<<"\n"; } - // histo file: + // histo file: parseVector("HISTOFILES",histoFiles); - if(histoFiles.size()==0){ - integratehisto=false; - }else{ - integratehisto=true; - for(unsigned i=0;i<histoFiles.size();i++) log<<" histofile : "<<histoFiles[i]<<"\n"; + if(histoFiles.size()==0) { + integratehisto=false; + } else { + integratehisto=true; + for(unsigned i=0; i<histoFiles.size(); i++) log<<" histofile : "<<histoFiles[i]<<"\n"; } vector<double> histoSigma; - if(integratehisto){ - parseVector("HISTOSIGMA",histoSigma); - for(unsigned i=0;i<histoSigma.size();i++) log<<" histosigma : "<<histoSigma[i]<<"\n"; + if(integratehisto) { + parseVector("HISTOSIGMA",histoSigma); + for(unsigned i=0; i<histoSigma.size(); i++) log<<" histosigma : "<<histoSigma[i]<<"\n"; } - // needs a projection? + // needs a projection? proj.clear(); parseVector("PROJ",proj); if(integratehills) { @@ -343,138 +344,141 @@ historep(NULL) plumed_massert(proj.size()<=getNumberOfArguments()," The number of projection must be less or equal to the full list of arguments "); } if(integratehisto&&proj.size()==0) { - for(unsigned i=0;i<getNumberOfArguments();i++) proj.push_back(getPntrToArgument(i)->getName()); + for(unsigned i=0; i<getNumberOfArguments(); i++) proj.push_back(getPntrToArgument(i)->getName()); } - // add some automatic hills width: not in case stride is defined + // add some automatic hills width: not in case stride is defined // since when you start from zero the automatic size will be zero! - if(gmin.size()==0 || gmax.size()==0){ - log<<" \n"; - log<<" No boundaries defined: need to do a prescreening of hills \n"; - std::vector<Value*> tmphillsvalues, tmphistovalues; - if(integratehills) { - for(unsigned i=0;i<getNumberOfArguments();i++)tmphillsvalues.push_back( getPntrToArgument(i) ); - } - if(integratehisto) { - for(unsigned i=0;i<getNumberOfArguments();i++) { - std::string ss = getPntrToArgument(i)->getName(); - for(unsigned j=0;j<proj.size();j++) { - if(proj[j]==ss) tmphistovalues.push_back( getPntrToArgument(i) ); - } - } + if(gmin.size()==0 || gmax.size()==0) { + log<<" \n"; + log<<" No boundaries defined: need to do a prescreening of hills \n"; + std::vector<Value*> tmphillsvalues, tmphistovalues; + if(integratehills) { + for(unsigned i=0; i<getNumberOfArguments(); i++)tmphillsvalues.push_back( getPntrToArgument(i) ); + } + if(integratehisto) { + for(unsigned i=0; i<getNumberOfArguments(); i++) { + std::string ss = getPntrToArgument(i)->getName(); + for(unsigned j=0; j<proj.size(); j++) { + if(proj[j]==ss) tmphistovalues.push_back( getPntrToArgument(i) ); } + } + } - if(integratehills) { - FilesHandler hillsHandler(hillsFiles,parallelread,*this, log); - vector<double> vmin,vmax; - vector<unsigned> vbin; - hillsHandler.getMinMaxBin(tmphillsvalues,comm,vmin,vmax,vbin); - log<<" found boundaries from hillsfile: \n"; - gmin.resize(vmin.size()); - gmax.resize(vmax.size()); - if(gbin.size()==0){ - gbin=vbin; - }else{ - log<<" found nbins in input, this overrides the automatic choice \n"; - } - for(unsigned i=0;i<getNumberOfArguments();i++){ - Tools::convert(vmin[i],gmin[i]); - Tools::convert(vmax[i],gmax[i]); - log<<" variable "<< getPntrToArgument(i)->getName()<<" min: "<<gmin[i]<<" max: "<<gmax[i]<<" nbin: "<<gbin[i]<<"\n"; - } - } - // if at this stage bins are not there then do it with histo - if(gmin.size()==0){ - FilesHandler histoHandler(histoFiles,parallelread,*this, log); - vector<double> vmin,vmax; - vector<unsigned> vbin; - histoHandler.getMinMaxBin(tmphistovalues,comm,vmin,vmax,vbin,histoSigma); - log<<" found boundaries from histofile: \n"; - gmin.resize(vmin.size()); - gmax.resize(vmax.size()); - if(gbin.size()==0){ - gbin=vbin; - }else{ - log<<" found nbins in input, this overrides the automatic choice \n"; - } - for(unsigned i=0;i<proj.size();i++){ - Tools::convert(vmin[i],gmin[i]); - Tools::convert(vmax[i],gmax[i]); - log<<" variable "<< proj[i] <<" min: "<<gmin[i]<<" max: "<<gmax[i]<<" nbin: "<<gbin[i]<<"\n"; - } - } - log<<" done!\n"; - log<<" \n"; + if(integratehills) { + FilesHandler hillsHandler(hillsFiles,parallelread,*this, log); + vector<double> vmin,vmax; + vector<unsigned> vbin; + hillsHandler.getMinMaxBin(tmphillsvalues,comm,vmin,vmax,vbin); + log<<" found boundaries from hillsfile: \n"; + gmin.resize(vmin.size()); + gmax.resize(vmax.size()); + if(gbin.size()==0) { + gbin=vbin; + } else { + log<<" found nbins in input, this overrides the automatic choice \n"; + } + for(unsigned i=0; i<getNumberOfArguments(); i++) { + Tools::convert(vmin[i],gmin[i]); + Tools::convert(vmax[i],gmax[i]); + log<<" variable "<< getPntrToArgument(i)->getName()<<" min: "<<gmin[i]<<" max: "<<gmax[i]<<" nbin: "<<gbin[i]<<"\n"; + } + } + // if at this stage bins are not there then do it with histo + if(gmin.size()==0) { + FilesHandler histoHandler(histoFiles,parallelread,*this, log); + vector<double> vmin,vmax; + vector<unsigned> vbin; + histoHandler.getMinMaxBin(tmphistovalues,comm,vmin,vmax,vbin,histoSigma); + log<<" found boundaries from histofile: \n"; + gmin.resize(vmin.size()); + gmax.resize(vmax.size()); + if(gbin.size()==0) { + gbin=vbin; + } else { + log<<" found nbins in input, this overrides the automatic choice \n"; + } + for(unsigned i=0; i<proj.size(); i++) { + Tools::convert(vmin[i],gmin[i]); + Tools::convert(vmax[i],gmax[i]); + log<<" variable "<< proj[i] <<" min: "<<gmin[i]<<" max: "<<gmax[i]<<" nbin: "<<gbin[i]<<"\n"; + } + } + log<<" done!\n"; + log<<" \n"; } if( proj.size() != 0 || integratehisto==true ) { parse("KT",beta); - for(unsigned i=0;i<proj.size();i++) log<<" projection "<<i<<" : "<<proj[i]<<"\n"; + for(unsigned i=0; i<proj.size(); i++) log<<" projection "<<i<<" : "<<proj[i]<<"\n"; // this should be only for projection or free energy from histograms - plumed_massert(beta>0.,"if you make a projection or a histogram correction then you need KT flag!"); - beta=1./beta; - log<<" beta is "<<beta<<"\n"; + plumed_massert(beta>0.,"if you make a projection or a histogram correction then you need KT flag!"); + beta=1./beta; + log<<" beta is "<<beta<<"\n"; } // is a cltool: then you start and then die parseFlag("ISCLTOOL",iscltool); - // - parseFlag("NEGBIAS",negativebias); + // + parseFlag("NEGBIAS",negativebias); // parseFlag("PARALLELREAD",parallelread); // stride parse("INITSTRIDE",initstride); // output suffix or names - if(initstride<0){ log<<" Doing only one integration: no stride \n"; - outhills="fes.dat";outhisto="histo.dat";} - else{outhills="fes_";outhisto="histo_"; - log<<" Doing integration slices every "<<initstride<<" kernels\n"; - parseFlag("NOHISTORY",nohistory); - if(nohistory)log<<" nohistory: each stride block has no memory of the previous block\n"; + if(initstride<0) { + log<<" Doing only one integration: no stride \n"; + outhills="fes.dat"; outhisto="histo.dat"; + } + else { + outhills="fes_"; outhisto="histo_"; + log<<" Doing integration slices every "<<initstride<<" kernels\n"; + parseFlag("NOHISTORY",nohistory); + if(nohistory)log<<" nohistory: each stride block has no memory of the previous block\n"; } parseFlag("MINTOZERO",minTOzero); if(minTOzero)log<<" mintozero: bias/histogram will be translated to have the minimum value equal to zero\n"; - //what might it be this? - // here start + //what might it be this? + // here start // want something right now?? do it and return - // your argument is a set of cvs - // then you need: a hills / a colvar-like file (to do a histogram) + // your argument is a set of cvs + // then you need: a hills / a colvar-like file (to do a histogram) // create a bias representation for this - if(iscltool){ + if(iscltool) { - std::vector<Value*> tmphillsvalues, tmphistovalues; + std::vector<Value*> tmphillsvalues, tmphistovalues; if(integratehills) { - for(unsigned i=0;i<getNumberOfArguments();i++){ + for(unsigned i=0; i<getNumberOfArguments(); i++) { // allocate a new value from the old one: no deriv here // if we are summing hills then all the arguments are needed - tmphillsvalues.push_back( getPntrToArgument(i) ); + tmphillsvalues.push_back( getPntrToArgument(i) ); } } if(integratehisto) { - for(unsigned i=0;i<getNumberOfArguments();i++) { - std::string ss = getPntrToArgument(i)->getName(); - for(unsigned j=0;j<proj.size();j++) { + for(unsigned i=0; i<getNumberOfArguments(); i++) { + std::string ss = getPntrToArgument(i)->getName(); + for(unsigned j=0; j<proj.size(); j++) { if(proj[j]==ss) tmphistovalues.push_back( getPntrToArgument(i) ); } - } + } } - // check if the files exists - if(integratehills){ - checkFilesAreExisting(hillsFiles); - biasrep=new BiasRepresentation(tmphillsvalues,comm, gmin, gmax, gbin, doInt, lowI_, uppI_); - if(negativebias){ - biasrep->setRescaledToBias(true); - log<<" required the -bias instead of the free energy \n"; - if(initstride<0){outhills="negativebias.dat";} - else{outhills="negativebias_";} - } + // check if the files exists + if(integratehills) { + checkFilesAreExisting(hillsFiles); + biasrep=new BiasRepresentation(tmphillsvalues,comm, gmin, gmax, gbin, doInt, lowI_, uppI_); + if(negativebias) { + biasrep->setRescaledToBias(true); + log<<" required the -bias instead of the free energy \n"; + if(initstride<0) {outhills="negativebias.dat";} + else {outhills="negativebias_";} + } } parse("OUTHILLS",outhills); parse("OUTHISTO",outhisto); - if(integratehills)log<<" output file for fes/bias is : "<<outhills<<"\n"; - if(integratehisto)log<<" output file for histogram is : "<<outhisto<<"\n"; + if(integratehills)log<<" output file for fes/bias is : "<<outhills<<"\n"; + if(integratehisto)log<<" output file for histogram is : "<<outhisto<<"\n"; checkRead(); log<<"\n"; @@ -483,15 +487,15 @@ historep(NULL) // here it defines the column to be histogrammed, tmpvalues should be only // the list of the collective variable one want to consider - if(integratehisto){ - checkFilesAreExisting(histoFiles); - historep=new BiasRepresentation(tmphistovalues,comm,gmin,gmax,gbin,histoSigma); + if(integratehisto) { + checkFilesAreExisting(histoFiles); + historep=new BiasRepresentation(tmphistovalues,comm,gmin,gmax,gbin,histoSigma); } // decide how to source hills ( serial/parallel ) - // here below the input control - // say how many hills and it will read them from the - // bunch of files provided, will update the representation + // here below the input control + // say how many hills and it will read them from the + // bunch of files provided, will update the representation // of hills (i.e. a list of hills and the associated grid) // decide how to source colvars ( serial parallel ) @@ -511,110 +515,110 @@ historep(NULL) // read a number of hills and put in the bias representation int nfiles=0; bool ibias=integratehills; bool ihisto=integratehisto; - while(true){ - if( integratehills && ibias ){ - if(nohistory){biasrep->clear();log<<" clearing history before reading a new block\n";}; - log<<" reading hills: \n"; - ibias=hillsHandler->readBunch(biasrep,initstride) ; log<<"\n"; - } - - if( integratehisto && ihisto ){ - if(nohistory){historep->clear();log<<" clearing history before reading a new block\n";}; - log<<" reading histogram: \n"; - ihisto=histoHandler->readBunch(historep,initstride) ; log<<"\n"; - } - - // dump: need to project? - if(proj.size()!=0){ - - if(integratehills){ - - log<<" Bias: Projecting on subgrid... \n"; - BiasWeight Bw(beta); - Grid biasGrid=*(biasrep->getGridPtr()); - Grid smallGrid=biasGrid.project(proj,&Bw); - OFile gridfile; gridfile.link(*this); - std::ostringstream ostr;ostr<<nfiles; - string myout; - if(initstride>0){ myout=outhills+ostr.str()+".dat" ;}else{myout=outhills;} - log<<" Bias: Writing subgrid on file "<<myout<<" \n"; - gridfile.open(myout); - if(minTOzero) smallGrid.setMinToZero(); - smallGrid.setOutputFmt(fmt); - smallGrid.writeToFile(gridfile); - gridfile.close(); - if(!ibias)integratehills=false;// once you get to the final bunch just give up - } - // this should be removed - if(integratehisto){ - - log<<" Histo: Projecting on subgrid... \n"; - Grid histoGrid=*(historep->getGridPtr()); - - OFile gridfile; gridfile.link(*this); - std::ostringstream ostr;ostr<<nfiles; - string myout; - if(initstride>0){ myout=outhisto+ostr.str()+".dat" ;}else{myout=outhisto;} - log<<" Histo: Writing subgrid on file "<<myout<<" \n"; - gridfile.open(myout); - - histoGrid.applyFunctionAllValuesAndDerivatives(&mylog,&mylogder); - histoGrid.scaleAllValuesAndDerivatives(-1./beta); - if(minTOzero) histoGrid.setMinToZero(); - histoGrid.setOutputFmt(fmt); - histoGrid.writeToFile(gridfile); - gridfile.close(); - - if(!ihisto)integratehisto=false;// once you get to the final bunch just give up - } - - }else{ - - if(integratehills){ - - Grid biasGrid=*(biasrep->getGridPtr()); - biasGrid.scaleAllValuesAndDerivatives(-1.); - - OFile gridfile; gridfile.link(*this); - std::ostringstream ostr;ostr<<nfiles; - string myout; - if(initstride>0){ myout=outhills+ostr.str()+".dat" ;}else{myout=outhills;} - log<<" Writing full grid on file "<<myout<<" \n"; - gridfile.open(myout); - - if(minTOzero) biasGrid.setMinToZero(); - biasGrid.setOutputFmt(fmt); - biasGrid.writeToFile(gridfile); - gridfile.close(); - // rescale back prior to accumulate - if(!ibias)integratehills=false;// once you get to the final bunch just give up - } - if(integratehisto){ - - Grid histoGrid=*(historep->getGridPtr()); - // do this if you want a free energy from a grid, otherwise do not - histoGrid.applyFunctionAllValuesAndDerivatives(&mylog,&mylogder); - histoGrid.scaleAllValuesAndDerivatives(-1./beta); - - OFile gridfile; gridfile.link(*this); - std::ostringstream ostr;ostr<<nfiles; - string myout; - if(initstride>0){ myout=outhisto+ostr.str()+".dat" ;}else{myout=outhisto;} - log<<" Writing full grid on file "<<myout<<" \n"; - gridfile.open(myout); - - // also this is usefull only for free energy - if(minTOzero) histoGrid.setMinToZero(); - histoGrid.setOutputFmt(fmt); - histoGrid.writeToFile(gridfile); - gridfile.close(); - - if(!ihisto)integratehisto=false; // once you get to the final bunch just give up - } - } - if ( !ibias && !ihisto) break; //when both are over then just quit - - nfiles++; + while(true) { + if( integratehills && ibias ) { + if(nohistory) {biasrep->clear(); log<<" clearing history before reading a new block\n";}; + log<<" reading hills: \n"; + ibias=hillsHandler->readBunch(biasrep,initstride) ; log<<"\n"; + } + + if( integratehisto && ihisto ) { + if(nohistory) {historep->clear(); log<<" clearing history before reading a new block\n";}; + log<<" reading histogram: \n"; + ihisto=histoHandler->readBunch(historep,initstride) ; log<<"\n"; + } + + // dump: need to project? + if(proj.size()!=0) { + + if(integratehills) { + + log<<" Bias: Projecting on subgrid... \n"; + BiasWeight Bw(beta); + Grid biasGrid=*(biasrep->getGridPtr()); + Grid smallGrid=biasGrid.project(proj,&Bw); + OFile gridfile; gridfile.link(*this); + std::ostringstream ostr; ostr<<nfiles; + string myout; + if(initstride>0) { myout=outhills+ostr.str()+".dat" ;} else {myout=outhills;} + log<<" Bias: Writing subgrid on file "<<myout<<" \n"; + gridfile.open(myout); + if(minTOzero) smallGrid.setMinToZero(); + smallGrid.setOutputFmt(fmt); + smallGrid.writeToFile(gridfile); + gridfile.close(); + if(!ibias)integratehills=false;// once you get to the final bunch just give up + } + // this should be removed + if(integratehisto) { + + log<<" Histo: Projecting on subgrid... \n"; + Grid histoGrid=*(historep->getGridPtr()); + + OFile gridfile; gridfile.link(*this); + std::ostringstream ostr; ostr<<nfiles; + string myout; + if(initstride>0) { myout=outhisto+ostr.str()+".dat" ;} else {myout=outhisto;} + log<<" Histo: Writing subgrid on file "<<myout<<" \n"; + gridfile.open(myout); + + histoGrid.applyFunctionAllValuesAndDerivatives(&mylog,&mylogder); + histoGrid.scaleAllValuesAndDerivatives(-1./beta); + if(minTOzero) histoGrid.setMinToZero(); + histoGrid.setOutputFmt(fmt); + histoGrid.writeToFile(gridfile); + gridfile.close(); + + if(!ihisto)integratehisto=false;// once you get to the final bunch just give up + } + + } else { + + if(integratehills) { + + Grid biasGrid=*(biasrep->getGridPtr()); + biasGrid.scaleAllValuesAndDerivatives(-1.); + + OFile gridfile; gridfile.link(*this); + std::ostringstream ostr; ostr<<nfiles; + string myout; + if(initstride>0) { myout=outhills+ostr.str()+".dat" ;} else {myout=outhills;} + log<<" Writing full grid on file "<<myout<<" \n"; + gridfile.open(myout); + + if(minTOzero) biasGrid.setMinToZero(); + biasGrid.setOutputFmt(fmt); + biasGrid.writeToFile(gridfile); + gridfile.close(); + // rescale back prior to accumulate + if(!ibias)integratehills=false;// once you get to the final bunch just give up + } + if(integratehisto) { + + Grid histoGrid=*(historep->getGridPtr()); + // do this if you want a free energy from a grid, otherwise do not + histoGrid.applyFunctionAllValuesAndDerivatives(&mylog,&mylogder); + histoGrid.scaleAllValuesAndDerivatives(-1./beta); + + OFile gridfile; gridfile.link(*this); + std::ostringstream ostr; ostr<<nfiles; + string myout; + if(initstride>0) { myout=outhisto+ostr.str()+".dat" ;} else {myout=outhisto;} + log<<" Writing full grid on file "<<myout<<" \n"; + gridfile.open(myout); + + // also this is usefull only for free energy + if(minTOzero) histoGrid.setMinToZero(); + histoGrid.setOutputFmt(fmt); + histoGrid.writeToFile(gridfile); + gridfile.close(); + + if(!ihisto)integratehisto=false; // once you get to the final bunch just give up + } + } + if ( !ibias && !ihisto) break; //when both are over then just quit + + nfiles++; } sw.stop("0 Summing hills"); @@ -622,34 +626,34 @@ historep(NULL) log<<sw; return; - } - // just an initialization but you need to do something on the fly?: need to connect with a metad run and its grid representation + } + // just an initialization but you need to do something on the fly?: need to connect with a metad run and its grid representation // your argument is a metad run - // if the grid does not exist crash and say that you need some data + // if the grid does not exist crash and say that you need some data // otherwise just link with it } -void FuncSumHills::calculate(){ - // this should be connected only with a grid representation to metadynamics +void FuncSumHills::calculate() { + // this should be connected only with a grid representation to metadynamics // at regular time just dump it - plumed_merror("You should have never got here: this stuff is not yet implemented!"); + plumed_merror("You should have never got here: this stuff is not yet implemented!"); } -FuncSumHills::~FuncSumHills(){ +FuncSumHills::~FuncSumHills() { if(historep) delete historep; if(biasrep) delete biasrep; } -bool FuncSumHills::checkFilesAreExisting(const vector<string> & hills ){ - plumed_massert(hills.size()!=0,"the number of files provided should be at least one" ); - IFile *ifile = new IFile(); - ifile->link(*this); - for(unsigned i=0; i< hills.size();i++){ - plumed_massert(ifile->FileExist(hills[i]),"missing file "+hills[i]); - } - delete ifile; - return true; +bool FuncSumHills::checkFilesAreExisting(const vector<string> & hills ) { + plumed_massert(hills.size()!=0,"the number of files provided should be at least one" ); + IFile *ifile = new IFile(); + ifile->link(*this); + for(unsigned i=0; i< hills.size(); i++) { + plumed_massert(ifile->FileExist(hills[i]),"missing file "+hills[i]); + } + delete ifile; + return true; } diff --git a/src/function/Function.cpp b/src/function/Function.cpp index 39b5ea82b..0852d3181 100644 --- a/src/function/Function.cpp +++ b/src/function/Function.cpp @@ -23,10 +23,10 @@ #include "tools/OpenMP.h" using namespace std; -namespace PLMD{ -namespace function{ +namespace PLMD { +namespace function { -void Function::registerKeywords(Keywords& keys){ +void Function::registerKeywords(Keywords& keys) { Action::registerKeywords(keys); ActionWithValue::registerKeywords(keys); ActionWithArguments::registerKeywords(keys); @@ -34,29 +34,29 @@ void Function::registerKeywords(Keywords& keys){ } Function::Function(const ActionOptions&ao): -Action(ao), -ActionWithValue(ao), -ActionWithArguments(ao) + Action(ao), + ActionWithValue(ao), + ActionWithArguments(ao) { } -void Function::addValueWithDerivatives(){ +void Function::addValueWithDerivatives() { plumed_massert( getNumberOfArguments()!=0, "for functions you must requestArguments before adding values"); - ActionWithValue::addValueWithDerivatives(); + ActionWithValue::addValueWithDerivatives(); getPntrToValue()->resizeDerivatives(getNumberOfArguments()); - if( keywords.exists("PERIODIC") ){ - std::vector<std::string> period; - parseVector("PERIODIC",period); - if(period.size()==1 && period[0]=="NO"){ - setNotPeriodic(); - } else if(period.size()==2){ - setPeriodic(period[0],period[1]); - } else error("missing PERIODIC keyword"); + if( keywords.exists("PERIODIC") ) { + std::vector<std::string> period; + parseVector("PERIODIC",period); + if(period.size()==1 && period[0]=="NO") { + setNotPeriodic(); + } else if(period.size()==2) { + setPeriodic(period[0],period[1]); + } else error("missing PERIODIC keyword"); } -} - -void Function::addComponentWithDerivatives( const std::string& name ){ +} + +void Function::addComponentWithDerivatives( const std::string& name ) { plumed_massert( getNumberOfArguments()!=0, "for functions you must requestArguments before adding values"); ActionWithValue::addComponentWithDerivatives(name); getPntrToComponent(name)->resizeDerivatives(getNumberOfArguments()); @@ -83,19 +83,19 @@ void Function::apply() vector<double> omp_f(noa,0.0); vector<double> forces(noa); #pragma omp for reduction( + : at_least_one_forced) - for(unsigned i=rank;i<ncp;i+=stride) { + for(unsigned i=rank; i<ncp; i+=stride) { if(getPntrToComponent(i)->applyForce(forces)) { at_least_one_forced+=1; - for(unsigned j=0;j<noa;j++) omp_f[j]+=forces[j]; + for(unsigned j=0; j<noa; j++) omp_f[j]+=forces[j]; } } #pragma omp critical - for(unsigned j=0;j<noa;j++) f[j]+=omp_f[j]; + for(unsigned j=0; j<noa; j++) f[j]+=omp_f[j]; } if(noa>0&&ncp>4*cgs) { comm.Sum(&f[0],noa); comm.Sum(at_least_one_forced); } - if(at_least_one_forced>0) for(unsigned i=0;i<noa;++i) getPntrToArgument(i)->addForce(f[i]); + if(at_least_one_forced>0) for(unsigned i=0; i<noa; ++i) getPntrToArgument(i)->addForce(f[i]); } } diff --git a/src/function/Function.h b/src/function/Function.h index e0dfae908..02215e1cc 100644 --- a/src/function/Function.h +++ b/src/function/Function.h @@ -26,12 +26,12 @@ #include "core/ActionWithArguments.h" #include "tools/Communicator.h" -namespace PLMD{ -namespace function{ +namespace PLMD { +namespace function { /** \ingroup INHERIT -This is the abstract base class to use for implementing new CV function, within it there is +This is the abstract base class to use for implementing new CV function, within it there is \ref AddingAFunction "information" as to how to go about implementing a new function. */ @@ -43,27 +43,27 @@ protected: void setDerivative(int,double); void setDerivative(Value*,int,double); void addValueWithDerivatives(); - void addComponentWithDerivatives( const std::string& name ); + void addComponentWithDerivatives( const std::string& name ); public: explicit Function(const ActionOptions&); - virtual ~Function(){} + virtual ~Function() {} void apply(); static void registerKeywords(Keywords&); unsigned getNumberOfDerivatives(); }; inline -void Function::setDerivative(Value*v,int i,double d){ +void Function::setDerivative(Value*v,int i,double d) { v->addDerivative(i,d); } inline -void Function::setDerivative(int i,double d){ +void Function::setDerivative(int i,double d) { setDerivative(getPntrToValue(),i,d); } inline -unsigned Function::getNumberOfDerivatives(){ +unsigned Function::getNumberOfDerivatives() { return getNumberOfArguments(); } diff --git a/src/function/LocalEnsemble.cpp b/src/function/LocalEnsemble.cpp index aee9a076f..6e3bd96f6 100644 --- a/src/function/LocalEnsemble.cpp +++ b/src/function/LocalEnsemble.cpp @@ -25,15 +25,15 @@ using namespace std; -namespace PLMD{ -namespace function{ +namespace PLMD { +namespace function { //+PLUMEDOC FUNCTION LOCALENSEMBLE /* Calculates the average over multiple arguments. If more than one collective variable is given for each argument then they -are averaged separately. The average is stored in a component labelled <em>label</em>.cvlabel. +are averaged separately. The average is stored in a component labelled <em>label</em>.cvlabel. \par Examples The following input tells plumed to calculate the chemical shifts for four @@ -88,7 +88,7 @@ public: PLUMED_REGISTER_ACTION(LocalEnsemble,"LOCALENSEMBLE") -void LocalEnsemble::registerKeywords(Keywords& keys){ +void LocalEnsemble::registerKeywords(Keywords& keys) { Function::registerKeywords(keys); keys.use("ARG"); keys.add("compulsory","NUM","the number of local replicas"); @@ -96,24 +96,24 @@ void LocalEnsemble::registerKeywords(Keywords& keys){ } LocalEnsemble::LocalEnsemble(const ActionOptions&ao): -Action(ao), -Function(ao), -ens_dim(0) + Action(ao), + Function(ao), + ens_dim(0) { parse("NUM",ens_dim); if(ens_dim==0) error("NUM should be greater or equal to 1"); vector<Value*> arg; int oldsize=-1; - for(unsigned i=1;i<=ens_dim;++i ){ + for(unsigned i=1; i<=ens_dim; ++i ) { vector<Value*> larg; if(!parseArgumentList("ARG",i,larg)) break; - for(unsigned j=0;j<larg.size();j++) arg.push_back(larg[j]); + for(unsigned j=0; j<larg.size(); j++) arg.push_back(larg[j]); if(oldsize!=-1&&oldsize!=larg.size()) error("In LOCALENSEMBLE you should have the same number of arguments for each ARG keyword"); oldsize = larg.size(); - if(!larg.empty()){ + if(!larg.empty()) { log.printf(" with arguments %u: ", i); - for(unsigned j=0;j<larg.size();j++) log.printf(" %s",larg[j]->getName().c_str()); + for(unsigned j=0; j<larg.size(); j++) log.printf(" %s",larg[j]->getName().c_str()); log.printf("\n"); } } @@ -121,9 +121,9 @@ ens_dim(0) narg = arg.size()/ens_dim; // these are the averages - for(unsigned i=0;i<narg;i++) { + for(unsigned i=0; i<narg; i++) { std::string s=getPntrToArgument(i)->getName(); - addComponentWithDerivatives(s); + addComponentWithDerivatives(s); getPntrToComponent(i)->setNotPeriodic(); } @@ -132,18 +132,18 @@ ens_dim(0) void LocalEnsemble::calculate() { - const double fact = 1.0/static_cast<double>(ens_dim); + const double fact = 1.0/static_cast<double>(ens_dim); #pragma omp parallel for num_threads(OpenMP::getNumThreads()) - for(unsigned i=0;i<narg;++i){ + for(unsigned i=0; i<narg; ++i) { double mean = 0.; Value* v=getPntrToComponent(i); - for(unsigned j=0;j<ens_dim;++j) { + for(unsigned j=0; j<ens_dim; ++j) { const unsigned index = j*narg+i; setDerivative(v, index, fact); mean += fact*getArgument(index); } v->set(mean); - } + } } } diff --git a/src/function/Matheval.cpp b/src/function/Matheval.cpp index 55a7f439e..59e6e9bf0 100644 --- a/src/function/Matheval.cpp +++ b/src/function/Matheval.cpp @@ -28,8 +28,8 @@ using namespace std; -namespace PLMD{ -namespace function{ +namespace PLMD { +namespace function { //+PLUMEDOC FUNCTION MATHEVAL @@ -186,7 +186,7 @@ public: #ifdef __PLUMED_HAS_MATHEVAL PLUMED_REGISTER_ACTION(Matheval,"MATHEVAL") -void Matheval::registerKeywords(Keywords& keys){ +void Matheval::registerKeywords(Keywords& keys) { Function::registerKeywords(keys); keys.use("ARG"); keys.use("PERIODIC"); keys.add("compulsory","FUNC","the function you wish to evaluate"); @@ -194,14 +194,14 @@ void Matheval::registerKeywords(Keywords& keys){ } Matheval::Matheval(const ActionOptions&ao): -Action(ao), -Function(ao), -evaluator_deriv(getNumberOfArguments()), -values(getNumberOfArguments()), -names(getNumberOfArguments()) + Action(ao), + Function(ao), + evaluator_deriv(getNumberOfArguments()), + values(getNumberOfArguments()), + names(getNumberOfArguments()) { parseVector("VAR",var); - if(var.size()==0){ + if(var.size()==0) { var.resize(getNumberOfArguments()); if(getNumberOfArguments()>3) error("Using more than 3 arguments you should explicitly write their names with VAR"); @@ -212,7 +212,7 @@ names(getNumberOfArguments()) if(var.size()!=getNumberOfArguments()) error("Size of VAR array should be the same as number of arguments"); parse("FUNC",func); - addValueWithDerivatives(); + addValueWithDerivatives(); checkRead(); evaluator=evaluator_create(const_cast<char*>(func.c_str())); @@ -222,46 +222,46 @@ names(getNumberOfArguments()) char **check_names; int check_count; evaluator_get_variables(evaluator,&check_names,&check_count); - if(check_count!=int(getNumberOfArguments())){ + if(check_count!=int(getNumberOfArguments())) { string sc; Tools::convert(check_count,sc); error("Your function string contains "+sc+" arguments. This should be equal to the number of ARGs"); } - for(unsigned i=0;i<getNumberOfArguments();i++){ + for(unsigned i=0; i<getNumberOfArguments(); i++) { bool found=false; - for(unsigned j=0;j<getNumberOfArguments();j++){ + for(unsigned j=0; j<getNumberOfArguments(); j++) { if(var[i]==check_names[j])found=true; } if(!found) error("Variable "+var[i]+" cannot be found in your function string"); } - for(unsigned i=0;i<getNumberOfArguments();i++) + for(unsigned i=0; i<getNumberOfArguments(); i++) evaluator_deriv[i]=evaluator_derivative(evaluator,const_cast<char*>(var[i].c_str())); log.printf(" with function : %s\n",func.c_str()); log.printf(" with variables :"); - for(unsigned i=0;i<var.size();i++) log.printf(" %s",var[i].c_str()); + for(unsigned i=0; i<var.size(); i++) log.printf(" %s",var[i].c_str()); log.printf("\n"); log.printf(" function as parsed by matheval: %s\n", evaluator_get_string(evaluator)); log.printf(" derivatives as computed by matheval:\n"); - for(unsigned i=0;i<var.size();i++) log.printf(" %s\n",evaluator_get_string(evaluator_deriv[i])); + for(unsigned i=0; i<var.size(); i++) log.printf(" %s\n",evaluator_get_string(evaluator_deriv[i])); } -void Matheval::calculate(){ - for(unsigned i=0;i<getNumberOfArguments();i++) values[i]=getArgument(i); - for(unsigned i=0;i<getNumberOfArguments();i++) names[i]=const_cast<char*>(var[i].c_str()); +void Matheval::calculate() { + for(unsigned i=0; i<getNumberOfArguments(); i++) values[i]=getArgument(i); + for(unsigned i=0; i<getNumberOfArguments(); i++) names[i]=const_cast<char*>(var[i].c_str()); setValue(evaluator_evaluate(evaluator,names.size(),&names[0],&values[0])); - for(unsigned i=0;i<getNumberOfArguments();i++){ + for(unsigned i=0; i<getNumberOfArguments(); i++) { setDerivative(i,evaluator_evaluate(evaluator_deriv[i],names.size(),&names[0],&values[0])); } } -Matheval::~Matheval(){ +Matheval::~Matheval() { evaluator_destroy(evaluator); - for(unsigned i=0;i<evaluator_deriv.size();i++)evaluator_destroy(evaluator_deriv[i]); + for(unsigned i=0; i<evaluator_deriv.size(); i++)evaluator_destroy(evaluator_deriv[i]); } #endif diff --git a/src/function/Piecewise.cpp b/src/function/Piecewise.cpp index 95b646fdd..e0f4bbd52 100644 --- a/src/function/Piecewise.cpp +++ b/src/function/Piecewise.cpp @@ -26,13 +26,13 @@ using namespace std; -namespace PLMD{ -namespace function{ +namespace PLMD { +namespace function { //+PLUMEDOC FUNCTION PIECEWISE /* Compute a piecewise straight line through its arguments that passes through -a set of ordered control points. +a set of ordered control points. For variables less than the first (greater than the last) point, the value of the first (last) point is used. @@ -41,10 +41,10 @@ For variables less than the first \frac{y_{i+1}-y_i}{x_{i+1}-x_i}(s-x_i)+y_i ; if x_i<s<x_{i+1} \f] \f[ -y_N ; if x>x_{N-1} +y_N ; if x>x_{N-1} \f] \f[ -y_1 ; if x<x_0 +y_1 ; if x<x_0 \f] Control points are passed using the POINT0=... POINT1=... syntax as in the example below @@ -83,39 +83,39 @@ public: PLUMED_REGISTER_ACTION(Piecewise,"PIECEWISE") -void Piecewise::registerKeywords(Keywords& keys){ +void Piecewise::registerKeywords(Keywords& keys) { Function::registerKeywords(keys); keys.use("ARG"); keys.add("numbered","POINT","This keyword is used to specify the various points in the function above."); keys.reset_style("POINT","compulsory"); componentsAreNotOptional(keys); keys.addOutputComponent("_pfunc","default","one or multiple instances of this quantity will be referenceable elsewhere " - "in the input file. These quantities will be named with the arguments of the " - "function followed by the character string _pfunc. These quantities tell the " - "user the values of the piecewise functions of each of the arguments."); + "in the input file. These quantities will be named with the arguments of the " + "function followed by the character string _pfunc. These quantities tell the " + "user the values of the piecewise functions of each of the arguments."); } Piecewise::Piecewise(const ActionOptions&ao): -Action(ao), -Function(ao) + Action(ao), + Function(ao) { - for(int i=0;;i++){ + for(int i=0;; i++) { std::vector<double> pp; if(!parseNumberedVector("POINT",i,pp) ) break; - if(pp.size()!=2) error("points should be in x,y format"); - points.push_back(std::pair<double,double>(pp[0],pp[1])); - if(i>0 && points[i].first<=points[i-1].first) error("points abscissas should be monotonously increasing"); + if(pp.size()!=2) error("points should be in x,y format"); + points.push_back(std::pair<double,double>(pp[0],pp[1])); + if(i>0 && points[i].first<=points[i-1].first) error("points abscissas should be monotonously increasing"); } - for(unsigned i=0;i<getNumberOfArguments();i++) + for(unsigned i=0; i<getNumberOfArguments(); i++) if(getPntrToArgument(i)->isPeriodic()) - error("Cannot use PIECEWISE on periodic arguments"); + error("Cannot use PIECEWISE on periodic arguments"); - if(getNumberOfArguments()==1){ - addValueWithDerivatives(); + if(getNumberOfArguments()==1) { + addValueWithDerivatives(); setNotPeriodic(); - }else{ - for(unsigned i=0;i<getNumberOfArguments();i++){ + } else { + for(unsigned i=0; i<getNumberOfArguments(); i++) { addComponentWithDerivatives( getPntrToArgument(i)->getName()+"_pfunc" ); getPntrToComponent(i)->setNotPeriodic(); } @@ -123,22 +123,22 @@ Function(ao) checkRead(); log.printf(" on points:"); - for(unsigned i=0;i<points.size();i++) log.printf(" (%f,%f)",points[i].first,points[i].second); + for(unsigned i=0; i<points.size(); i++) log.printf(" (%f,%f)",points[i].first,points[i].second); log.printf("\n"); } -void Piecewise::calculate(){ - for(unsigned i=0;i<getNumberOfArguments();i++){ +void Piecewise::calculate() { + for(unsigned i=0; i<getNumberOfArguments(); i++) { double val=getArgument(i); unsigned p=0; - for(;p<points.size();p++){ + for(; p<points.size(); p++) { if(val<points[p].first) break; } double f,d; - if(p==0){ + if(p==0) { f=points[0].second; d=0.0; - } else if(p==points.size()){ + } else if(p==points.size()) { f=points[points.size()-1].second; d=0.0; } else { diff --git a/src/function/Sort.cpp b/src/function/Sort.cpp index 36fb5da6c..f1e9b2a71 100644 --- a/src/function/Sort.cpp +++ b/src/function/Sort.cpp @@ -28,8 +28,8 @@ using namespace std; -namespace PLMD{ -namespace function{ +namespace PLMD { +namespace function { //+PLUMEDOC FUNCTION SORT /* @@ -37,8 +37,8 @@ This function can be used to sort colvars according to their magnitudes. \par Description of components -This function sorts its arguments according to their magnitudes. The lowest argument will be -labelled <em>label</em>.1, the second lowest will be labelled <em>label</em>.2 and so on. +This function sorts its arguments according to their magnitudes. The lowest argument will be +labelled <em>label</em>.1, the second lowest will be labelled <em>label</em>.2 and so on. \par Examples The following input tells plumed to print the distance of the closest and of @@ -69,38 +69,38 @@ public: PLUMED_REGISTER_ACTION(Sort,"SORT") -void Sort::registerKeywords(Keywords& keys){ +void Sort::registerKeywords(Keywords& keys) { Function::registerKeywords(keys); keys.use("ARG"); ActionWithValue::useCustomisableComponents(keys); } Sort::Sort(const ActionOptions&ao): -Action(ao), -Function(ao) + Action(ao), + Function(ao) { - for(unsigned i=0;i<getNumberOfArguments();++i){ + for(unsigned i=0; i<getNumberOfArguments(); ++i) { string s; Tools::convert(i+1,s); if(getPntrToArgument(i)->isPeriodic()) error("Cannot sort periodic values (check argument "+s+")"); - addComponentWithDerivatives(s); + addComponentWithDerivatives(s); getPntrToComponent(i)->setNotPeriodic(); } checkRead(); } -void Sort::calculate(){ +void Sort::calculate() { vector<pair<double,int> > vals(getNumberOfArguments()); - for(unsigned i=0;i<getNumberOfArguments();++i){ + for(unsigned i=0; i<getNumberOfArguments(); ++i) { vals[i].first=getArgument(i); // In this manner I remember from which argument the component depends: vals[i].second=i; } // STL sort sorts based on first element (value) then second (index) sort(vals.begin(),vals.end()); - for(int i=0;i<getNumberOfComponents();++i){ + for(int i=0; i<getNumberOfComponents(); ++i) { Value* v=getPntrToComponent(i); v->set(vals[i].first); setDerivative(v,vals[i].second,1.0); diff --git a/src/function/Stats.cpp b/src/function/Stats.cpp index c9f5ef804..429442e6d 100644 --- a/src/function/Stats.cpp +++ b/src/function/Stats.cpp @@ -24,8 +24,8 @@ using namespace std; -namespace PLMD{ -namespace function{ +namespace PLMD { +namespace function { //+PLUMEDOC FUNCTION STATS /* @@ -38,7 +38,7 @@ from other actions using PARARG (for example using experimental values from coll \ref CS2BACKBONE, \ref RDC, \ref NOE, \ref PRE). \par Examples -The following input tells plumed to print the distance between three couple of atoms +The following input tells plumed to print the distance between three couple of atoms and compare them with three reference distances. \verbatim @@ -69,28 +69,28 @@ public: PLUMED_REGISTER_ACTION(Stats,"STATS") -void Stats::registerKeywords(Keywords& keys){ +void Stats::registerKeywords(Keywords& keys) { Function::registerKeywords(keys); useCustomisableComponents(keys); keys.use("ARG"); - keys.add("optional","PARARG","the input for this action is the scalar output from one or more other actions without derivatives."); + keys.add("optional","PARARG","the input for this action is the scalar output from one or more other actions without derivatives."); keys.add("optional","PARAMETERS","the parameters of the arguments in your function"); keys.addFlag("SQDEVSUM",false,"calculates only SQDEVSUM"); keys.addFlag("SQDEV",false,"calculates and store the SQDEV as components"); keys.addFlag("UPPERDISTS",false,"calculates and store the SQDEV as components"); - keys.addOutputComponent("sqdevsum","default","the sum of the squared deviations between arguments and parameters"); - keys.addOutputComponent("corr","default","the correlation between arguments and parameters"); - keys.addOutputComponent("slope","default","the slope of a linear fit between arguments and parameters"); - keys.addOutputComponent("intercept","default","the intercept of a linear fit between arguments and parameters"); - keys.addOutputComponent("sqd","SQDEV","the squared deviations between arguments and parameters"); + keys.addOutputComponent("sqdevsum","default","the sum of the squared deviations between arguments and parameters"); + keys.addOutputComponent("corr","default","the correlation between arguments and parameters"); + keys.addOutputComponent("slope","default","the slope of a linear fit between arguments and parameters"); + keys.addOutputComponent("intercept","default","the intercept of a linear fit between arguments and parameters"); + keys.addOutputComponent("sqd","SQDEV","the squared deviations between arguments and parameters"); } Stats::Stats(const ActionOptions&ao): -Action(ao), -Function(ao), -sqdonly(false), -components(false), -upperd(false) + Action(ao), + Function(ao), + sqdonly(false), + components(false), + upperd(false) { parseVector("PARAMETERS",parameters); if(parameters.size()!=static_cast<unsigned>(getNumberOfArguments())&&!parameters.empty()) @@ -102,13 +102,13 @@ upperd(false) if(!arg2.empty()) { if(parameters.size()>0) error("It is not possible to use PARARG and PARAMETERS together"); if(arg2.size()!=getNumberOfArguments()) error("Size of PARARG array should be the same as number for arguments in ARG"); - for(unsigned i=0;i<arg2.size();i++){ - parameters.push_back(arg2[i]->get()); + for(unsigned i=0; i<arg2.size(); i++) { + parameters.push_back(arg2[i]->get()); if(arg2[i]->hasDerivatives()==true) error("PARARG can only accept arguments without derivatives"); } } - if(parameters.size()!=getNumberOfArguments()) + if(parameters.size()!=getNumberOfArguments()) error("PARARG or PARAMETERS arrays should include the same number of elements as the arguments in ARG"); if(getNumberOfArguments()<2) error("STATS need at least two arguments to be used"); @@ -123,12 +123,12 @@ upperd(false) if(!arg2.empty()) log.printf(" using %zu parameters from inactive actions:", arg2.size()); else log.printf(" using %zu parameters:", arg2.size()); - for(unsigned i=0;i<parameters.size();i++) log.printf(" %f",parameters[i]); + for(unsigned i=0; i<parameters.size(); i++) log.printf(" %f",parameters[i]); log.printf("\n"); if(sqdonly) { if(components) { - for(unsigned i=0;i<parameters.size();i++) { + for(unsigned i=0; i<parameters.size(); i++) { std::string num; Tools::convert(i,num); addComponentWithDerivatives("sqd_"+num); componentIsNotPeriodic("sqd_"+num); @@ -159,13 +159,13 @@ void Stats::calculate() double nsqd = 0.; Value* val; if(!components) val=getPntrToComponent("sqdevsum"); - for(unsigned i=0;i<parameters.size();++i){ + for(unsigned i=0; i<parameters.size(); ++i) { double dev = getArgument(i)-parameters[i]; - if(upperd&&dev<0) dev=0.; + if(upperd&&dev<0) dev=0.; if(components) { val=getPntrToComponent(i); val->set(dev*dev); - } else { + } else { nsqd += dev*dev; } setDerivative(val,i,2.*dev); @@ -175,8 +175,8 @@ void Stats::calculate() } else { double scx=0., scx2=0., scy=0., scy2=0., scxy=0.; - - for(unsigned i=0;i<parameters.size();++i){ + + for(unsigned i=0; i<parameters.size(); ++i) { const double tmpx=getArgument(i); const double tmpy=parameters[i]; scx += tmpx; @@ -185,7 +185,7 @@ void Stats::calculate() scy2 += tmpy*tmpy; scxy += tmpx*tmpy; } - + const double ns = parameters.size(); const double num = ns*scxy - scx*scy; @@ -212,7 +212,7 @@ void Stats::calculate() valued->set(inter); /* derivatives */ - for(unsigned i=0;i<parameters.size();++i){ + for(unsigned i=0; i<parameters.size(); ++i) { const double common_d1 = (ns*parameters[i]-scy)*idevx; const double common_d2 = num*(ns*getArgument(i)-scx)*idev2x*idevx; const double common_d3 = common_d1 - common_d2; diff --git a/src/function/Target.cpp b/src/function/Target.cpp index 8093da167..12630e43b 100644 --- a/src/function/Target.cpp +++ b/src/function/Target.cpp @@ -30,11 +30,11 @@ using namespace std; namespace PLMD { -namespace function{ +namespace function { //+PLUMEDOC DCOLVAR TARGET /* -This function measures the pythagorean distance from a particular structure measured in the space defined by some +This function measures the pythagorean distance from a particular structure measured in the space defined by some set of collective variables. This collective variable can be used to calculate something akin to: @@ -43,7 +43,7 @@ This collective variable can be used to calculate something akin to: d(X,X') = \vert X - X' \vert \f] -where \f$ X \f$ is the instaneous values for a set of collective variables for the system and +where \f$ X \f$ is the instaneous values for a set of collective variables for the system and \f$ X' \f$ is the values that these self-same set of collective variables take in some reference structure provided as input. If we call our set of collective variables \f$\{s_i\}f\$ then this CV computes: @@ -67,7 +67,7 @@ d = \left( \mathbf{s} - \mathbf{s}^{(ref)} \right)^T \mathbf{\Sigma} \left( \mat \f] where \f$\mathbf{s}\f$ is a column vector containing the values of all the CVs and \f$\mathbf{s}^{(ref)}\f$ is a column vector -containg the values of the CVs in the reference configuration. \f$\mathbf{\Sigma}\f$ is then an \f$N \times N\f$ matrix that is +containg the values of the CVs in the reference configuration. \f$\mathbf{\Sigma}\f$ is then an \f$N \times N\f$ matrix that is specified in the input. \par Examples @@ -82,14 +82,14 @@ t1: TARGET REFERENCE=myref.pdb TYPE=EUCLIDEAN PRINT ARG=t1 FILE=colvar \endverbatim -The contents of the file containing the reference structure (myref.pdb) is shown below. As you can see you must provide information on the -labels of the CVs that are being used to define the position of the reference configuration in this file together with the values that these +The contents of the file containing the reference structure (myref.pdb) is shown below. As you can see you must provide information on the +labels of the CVs that are being used to define the position of the reference configuration in this file together with the values that these quantities take in the reference configuration. \verbatim DESCRIPTION: a reference point. -REMARK WEIGHT=1.0 -REMARK ARG=d1,d2 +REMARK WEIGHT=1.0 +REMARK ARG=d1,d2 REMARK d1=1.0 d2=1.0 END \endverbatim @@ -111,28 +111,28 @@ public: PLUMED_REGISTER_ACTION(Target,"TARGET") -void Target::registerKeywords(Keywords& keys){ - Function::registerKeywords(keys); +void Target::registerKeywords(Keywords& keys) { + Function::registerKeywords(keys); keys.add("compulsory","TYPE","EUCLIDEAN","the manner in which the distance should be calculated"); keys.add("compulsory","REFERENCE","a file in pdb format containing the reference structure. In the PDB file the atomic " - "coordinates and box lengths should be in Angstroms unless you are working with natural units. " - "If you are working with natural units then the coordinates should be in your natural length unit. " - "The charges and masses of the atoms (if required) should be inserted in the beta and occupancy " - "columns respectively. For more details on the PDB file format visit http://www.wwpdb.org/docs.html"); + "coordinates and box lengths should be in Angstroms unless you are working with natural units. " + "If you are working with natural units then the coordinates should be in your natural length unit. " + "The charges and masses of the atoms (if required) should be inserted in the beta and occupancy " + "columns respectively. For more details on the PDB file format visit http://www.wwpdb.org/docs.html"); } Target::Target(const ActionOptions&ao): -Action(ao), -Function(ao), -myvals(1,0), -mypack(0,0,myvals) + Action(ao), + Function(ao), + myvals(1,0), + mypack(0,0,myvals) { std::string type; parse("TYPE",type); - std::string reference; parse("REFERENCE",reference); - checkRead(); PDB pdb; + std::string reference; parse("REFERENCE",reference); + checkRead(); PDB pdb; if( !pdb.read(reference,plumed.getAtoms().usingNaturalUnits(),0.1/plumed.getAtoms().getUnits().getLength()) ) - error("missing input file " + reference); - + error("missing input file " + reference); + // Use the base ActionWithArguments to expand things like a1.* expandArgKeywordInPDB( pdb ); @@ -155,14 +155,14 @@ mypack(0,0,myvals) // Create the value addValueWithDerivatives(); setNotPeriodic(); } - -Target::~Target(){ + +Target::~Target() { delete target; } -void Target::calculate(){ +void Target::calculate() { mypack.clear(); double r=target->calculate( getArguments(), mypack, false ); setValue(r); - for(unsigned i=0;i<getNumberOfArguments();i++) setDerivative( i, mypack.getArgumentDerivative(i) ); + for(unsigned i=0; i<getNumberOfArguments(); i++) setDerivative( i, mypack.getArgumentDerivative(i) ); } } diff --git a/src/generic/Debug.cpp b/src/generic/Debug.cpp index e9eb1e0b2..742b3b854 100644 --- a/src/generic/Debug.cpp +++ b/src/generic/Debug.cpp @@ -26,7 +26,7 @@ using namespace std; -namespace PLMD{ +namespace PLMD { namespace generic { //+PLUMEDOC GENERIC DEBUG @@ -56,15 +56,15 @@ class Debug: bool detailedTimers; public: explicit Debug(const ActionOptions&ao); -/// Register all the relevant keywords for the action +/// Register all the relevant keywords for the action static void registerKeywords( Keywords& keys ); - void calculate(){} + void calculate() {} void apply(); }; PLUMED_REGISTER_ACTION(Debug,"DEBUG") -void Debug::registerKeywords( Keywords& keys ){ +void Debug::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionPilot::registerKeywords(keys); keys.add("compulsory","STRIDE","1","the frequency with which this action is to be performed"); @@ -76,11 +76,11 @@ void Debug::registerKeywords( Keywords& keys ){ } Debug::Debug(const ActionOptions&ao): -Action(ao), -ActionPilot(ao), -logActivity(false), -logRequestedAtoms(false), -novirial(false){ + Action(ao), + ActionPilot(ao), + logActivity(false), + logRequestedAtoms(false), + novirial(false) { parseFlag("logActivity",logActivity); if(logActivity) log.printf(" logging activity\n"); parseFlag("logRequestedAtoms",logRequestedAtoms); @@ -94,7 +94,7 @@ novirial(false){ ofile.link(*this); std::string file; parse("FILE",file); - if(file.length()>0){ + if(file.length()>0) { ofile.open(file); log.printf(" on file %s\n",file.c_str()); } else { @@ -104,17 +104,17 @@ novirial(false){ checkRead(); } -void Debug::apply(){ - if(logActivity){ +void Debug::apply() { + if(logActivity) { const ActionSet&actionSet(plumed.getActionSet()); int a=0; - for(const auto & p : actionSet){ + for(const auto & p : actionSet) { if(dynamic_cast<Debug*>(p))continue; if(p->isActive()) a++; }; - if(a>0){ + if(a>0) { ofile.printf("activity at step %i: ",getStep()); - for(const auto & p : actionSet){ + for(const auto & p : actionSet) { if(dynamic_cast<Debug*>(p))continue; if(p->isActive()) ofile.printf("+"); else ofile.printf("-"); @@ -122,13 +122,13 @@ void Debug::apply(){ ofile.printf("\n"); }; }; - if(logRequestedAtoms){ + if(logRequestedAtoms) { ofile.printf("requested atoms at step %i: ",getStep()); int* l; int n; plumed.cmd("createFullList",&n); plumed.cmd("getFullList",&l); - for(int i=0;i<n;i++) ofile.printf(" %d",l[i]); + for(int i=0; i<n; i++) ofile.printf(" %d",l[i]); ofile.printf("\n"); plumed.cmd("clearFullList"); } diff --git a/src/generic/DumpAtoms.cpp b/src/generic/DumpAtoms.cpp index 2358cbe30..d6ee37748 100644 --- a/src/generic/DumpAtoms.cpp +++ b/src/generic/DumpAtoms.cpp @@ -41,7 +41,7 @@ using namespace std; namespace PLMD { -namespace generic{ +namespace generic { //+PLUMEDOC PRINTANALYSIS DUMPATOMS /* @@ -115,14 +115,14 @@ public: explicit DumpAtoms(const ActionOptions&); ~DumpAtoms(); static void registerKeywords( Keywords& keys ); - void calculate(){} - void apply(){} + void calculate() {} + void apply() {} void update(); }; PLUMED_REGISTER_ACTION(DumpAtoms,"DUMPATOMS") -void DumpAtoms::registerKeywords( Keywords& keys ){ +void DumpAtoms::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionPilot::registerKeywords( keys ); ActionAtomistic::registerKeywords( keys ); @@ -151,13 +151,13 @@ DumpAtoms::DumpAtoms(const ActionOptions&ao): string file; parse("FILE",file); if(file.length()==0) error("name out output file was not specified"); - type=Tools::extension(file); - log<<" file name "<<file<<"\n"; + type=Tools::extension(file); + log<<" file name "<<file<<"\n"; if(type=="gro" || type=="xyz" #ifdef __PLUMED_HAS_XDRFILE - || type=="xtc" || type=="trr" + || type=="xtc" || type=="trr" #endif - ){ + ) { log<<" file extension indicates a "<<type<<" file\n"; } else { log<<" file extension not detected, assuming xyz\n"; @@ -165,12 +165,12 @@ DumpAtoms::DumpAtoms(const ActionOptions&ao): } string ntype; parse("TYPE",ntype); - if(ntype.length()>0){ + if(ntype.length()>0) { if(ntype!="xyz" && ntype!="gro" #ifdef __PLUMED_HAS_XDRFILE - && ntype!="xtc" && ntype!="trr" + && ntype!="xtc" && ntype!="trr" #endif - ) error("TYPE cannot be understood"); + ) error("TYPE cannot be understood"); log<<" file type enforced to be "<<ntype<<"\n"; type=ntype; } @@ -181,7 +181,7 @@ DumpAtoms::DumpAtoms(const ActionOptions&ao): string precision; parse("PRECISION",precision); - if(precision.length()>0){ + if(precision.length()>0) { Tools::convert(precision,iprecision); log<<" with precision "<<iprecision<<"\n"; string a,b; @@ -195,13 +195,13 @@ DumpAtoms::DumpAtoms(const ActionOptions&ao): parseAtomList("ATOMS",atoms); std::string unitname; parse("UNITS",unitname); - if(unitname!="PLUMED"){ + if(unitname!="PLUMED") { Units myunit; myunit.setLength(unitname); if(myunit.getLength()!=1.0 && type=="gro") error("gro files should be in nm"); if(myunit.getLength()!=1.0 && type=="xtc") error("xtc files should be in nm"); if(myunit.getLength()!=1.0 && type=="trr") error("trr files should be in nm"); lenunit=plumed.getAtoms().getUnits().getLength()/myunit.getLength(); - } else if(type=="gro" || type=="xtc" || type=="trr") lenunit=plumed.getAtoms().getUnits().getLength(); + } else if(type=="gro" || type=="xtc" || type=="trr") lenunit=plumed.getAtoms().getUnits().getLength(); else lenunit=1.0; checkRead(); @@ -211,54 +211,54 @@ DumpAtoms::DumpAtoms(const ActionOptions&ao): log<<" Writing on file "<<path<<"\n"; #ifdef __PLUMED_HAS_XDRFILE std::string mode=of.getMode(); - if(type=="xtc"){ + if(type=="xtc") { of.close(); xd=xdrfile_open(path.c_str(),mode.c_str()); - } else if(type=="trr"){ + } else if(type=="trr") { of.close(); xd=xdrfile_open(path.c_str(),mode.c_str()); } #endif log.printf(" printing the following atoms in %s :", unitname.c_str() ); - for(unsigned i=0;i<atoms.size();++i) log.printf(" %d",atoms[i].serial() ); + for(unsigned i=0; i<atoms.size(); ++i) log.printf(" %d",atoms[i].serial() ); log.printf("\n"); requestAtoms(atoms); std::vector<SetupMolInfo*> moldat=plumed.getActionSet().select<SetupMolInfo*>(); - if( moldat.size()==1 ){ + if( moldat.size()==1 ) { log<<" MOLINFO DATA found, using proper atom names\n"; names.resize(atoms.size()); - for(unsigned i=0;i<atoms.size();i++) names[i]=moldat[0]->getAtomName(atoms[i]); + for(unsigned i=0; i<atoms.size(); i++) names[i]=moldat[0]->getAtomName(atoms[i]); residueNumbers.resize(atoms.size()); - for(unsigned i=0;i<residueNumbers.size();++i) residueNumbers[i]=moldat[0]->getResidueNumber(atoms[i]); + for(unsigned i=0; i<residueNumbers.size(); ++i) residueNumbers[i]=moldat[0]->getResidueNumber(atoms[i]); residueNames.resize(atoms.size()); - for(unsigned i=0;i<residueNames.size();++i) residueNames[i]=moldat[0]->getResidueName(atoms[i]); + for(unsigned i=0; i<residueNames.size(); ++i) residueNames[i]=moldat[0]->getResidueName(atoms[i]); } } -void DumpAtoms::update(){ - if(type=="xyz"){ +void DumpAtoms::update() { + if(type=="xyz") { of.printf("%d\n",getNumberOfAtoms()); const Tensor & t(getPbc().getBox()); - if(getPbc().isOrthorombic()){ + if(getPbc().isOrthorombic()) { of.printf((" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+"\n").c_str(),lenunit*t(0,0),lenunit*t(1,1),lenunit*t(2,2)); - }else{ + } else { of.printf((" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+"\n").c_str(), - lenunit*t(0,0),lenunit*t(0,1),lenunit*t(0,2), - lenunit*t(1,0),lenunit*t(1,1),lenunit*t(1,2), - lenunit*t(2,0),lenunit*t(2,1),lenunit*t(2,2) - ); + lenunit*t(0,0),lenunit*t(0,1),lenunit*t(0,2), + lenunit*t(1,0),lenunit*t(1,1),lenunit*t(1,2), + lenunit*t(2,0),lenunit*t(2,1),lenunit*t(2,2) + ); } - for(unsigned i=0;i<getNumberOfAtoms();++i){ + for(unsigned i=0; i<getNumberOfAtoms(); ++i) { const char* defname="X"; const char* name=defname; if(names.size()>0) if(names[i].length()>0) name=names[i].c_str(); of.printf(("%s "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+"\n").c_str(),name,lenunit*getPosition(i)(0),lenunit*getPosition(i)(1),lenunit*getPosition(i)(2)); } - } else if(type=="gro"){ + } else if(type=="gro") { const Tensor & t(getPbc().getBox()); of.printf("Made with PLUMED t=%f\n",getTime()/plumed.getAtoms().getUnits().getTime()); of.printf("%d\n",getNumberOfAtoms()); - for(unsigned i=0;i<getNumberOfAtoms();++i){ + for(unsigned i=0; i<getNumberOfAtoms(); ++i) { const char* defname="X"; const char* name=defname; unsigned residueNumber=0; @@ -267,29 +267,29 @@ void DumpAtoms::update(){ std::string resname=""; if(residueNames.size()>0) resname=residueNames[i]; of.printf(("%5u%-5s%5s%5d"+fmt_gro_pos+fmt_gro_pos+fmt_gro_pos+"\n").c_str(), - residueNumber%100000,resname.c_str(),name,getAbsoluteIndex(i).serial()%100000, - lenunit*getPosition(i)(0),lenunit*getPosition(i)(1),lenunit*getPosition(i)(2)); + residueNumber%100000,resname.c_str(),name,getAbsoluteIndex(i).serial()%100000, + lenunit*getPosition(i)(0),lenunit*getPosition(i)(1),lenunit*getPosition(i)(2)); } of.printf((fmt_gro_box+" "+fmt_gro_box+" "+fmt_gro_box+" "+fmt_gro_box+" "+fmt_gro_box+" "+fmt_gro_box+" "+fmt_gro_box+" "+fmt_gro_box+" "+fmt_gro_box+"\n").c_str(), - lenunit*t(0,0),lenunit*t(1,1),lenunit*t(2,2), - lenunit*t(0,1),lenunit*t(0,2),lenunit*t(1,0), - lenunit*t(1,2),lenunit*t(2,0),lenunit*t(2,1)); + lenunit*t(0,0),lenunit*t(1,1),lenunit*t(2,2), + lenunit*t(0,1),lenunit*t(0,2),lenunit*t(1,0), + lenunit*t(1,2),lenunit*t(2,0),lenunit*t(2,1)); #if defined(__PLUMED_HAS_XDRFILE) - } else if(type=="xtc" || type=="trr"){ + } else if(type=="xtc" || type=="trr") { matrix box; const Tensor & t(getPbc().getBox()); int natoms=getNumberOfAtoms(); int step=getStep(); float time=getTime()/plumed.getAtoms().getUnits().getTime(); float precision=Tools::fastpow(10.0,iprecision); - for(int i=0;i<3;i++) for(int j=0;j<3;j++) box[i][j]=lenunit*t(i,j); + for(int i=0; i<3; i++) for(int j=0; j<3; j++) box[i][j]=lenunit*t(i,j); rvec* pos=new rvec [natoms]; // Notice that code below cannot throw any exception. // Thus, this pointer is excepton safe - for(int i=0;i<natoms;i++) for(int j=0;j<3;j++) pos[i][j]=lenunit*getPosition(i)(j); - if(type=="xtc"){ + for(int i=0; i<natoms; i++) for(int j=0; j<3; j++) pos[i][j]=lenunit*getPosition(i)(j); + if(type=="xtc") { write_xtc(xd,natoms,step,time,box,&pos[0],precision); - } else if(type=="trr"){ + } else if(type=="trr") { write_trr(xd,natoms,step,time,0.0,box,&pos[0],NULL,NULL); } delete [] pos; @@ -297,7 +297,7 @@ void DumpAtoms::update(){ } else plumed_merror("unknown file type "+type); } -DumpAtoms::~DumpAtoms(){ +DumpAtoms::~DumpAtoms() { #ifdef __PLUMED_HAS_XDRFILE if(type=="xtc") { xdrfile_close(xd); @@ -306,7 +306,7 @@ DumpAtoms::~DumpAtoms(){ } #endif } - + } } diff --git a/src/generic/DumpDerivatives.cpp b/src/generic/DumpDerivatives.cpp index ab4fede99..c74343aca 100644 --- a/src/generic/DumpDerivatives.cpp +++ b/src/generic/DumpDerivatives.cpp @@ -27,20 +27,20 @@ using namespace std; -namespace PLMD{ -namespace generic{ +namespace PLMD { +namespace generic { //+PLUMEDOC PRINTANALYSIS DUMPDERIVATIVES /* Dump the derivatives with respect to the input parameters for one or more objects (generally CVs, functions or biases). -For a CV this line in input instructs plumed to print the derivative of the CV with respect to the atom positions +For a CV this line in input instructs plumed to print the derivative of the CV with respect to the atom positions and the cell vectors (virial-like form). In contrast, for a function or bias the derivative with respect to the input "CVs" will be output. This command is most often used to test whether or not analytic derivatives have been implemented correctly. This can be done by outputting the derivatives calculated analytically and numerically. You can control the buffering of output using the \ref FLUSH keyword. \par Examples -The following input instructs plumed to write a file called deriv that contains both the +The following input instructs plumed to write a file called deriv that contains both the analytical and numerical derivatives of the distance between atoms 1 and 2. \verbatim DISTANCE ATOM=1,2 LABEL=distance @@ -54,24 +54,24 @@ DUMPDERIVATIVES ARG=distance,distanceN STRIDE=1 FILE=deriv //+ENDPLUMEDOC class DumpDerivatives : -public ActionPilot, -public ActionWithArguments + public ActionPilot, + public ActionWithArguments { string file; string fmt; OFile of; public: - void calculate(){} + void calculate() {} explicit DumpDerivatives(const ActionOptions&); static void registerKeywords(Keywords& keys); - void apply(){} + void apply() {} void update(); ~DumpDerivatives(); }; PLUMED_REGISTER_ACTION(DumpDerivatives,"DUMPDERIVATIVES") -void DumpDerivatives::registerKeywords(Keywords& keys){ +void DumpDerivatives::registerKeywords(Keywords& keys) { Action::registerKeywords(keys); ActionPilot::registerKeywords(keys); ActionWithArguments::registerKeywords(keys); @@ -85,10 +85,10 @@ void DumpDerivatives::registerKeywords(Keywords& keys){ } DumpDerivatives::DumpDerivatives(const ActionOptions&ao): -Action(ao), -ActionPilot(ao), -ActionWithArguments(ao), -fmt("%15.10f") + Action(ao), + ActionPilot(ao), + ActionWithArguments(ao), + fmt("%15.10f") { parse("FILE",file); if( file.length()==0 ) error("name of output file was not specified"); @@ -103,21 +103,21 @@ fmt("%15.10f") (getPntrToArgument(0)->getPntrToAction())->turnOnDerivatives(); unsigned npar=getPntrToArgument(0)->getNumberOfDerivatives(); if( npar==0 ) error("one or more arguments has no derivatives"); - for(unsigned i=1;i<nargs;i++){ - (getPntrToArgument(i)->getPntrToAction())->turnOnDerivatives(); - if( npar!=getPntrToArgument(i)->getNumberOfDerivatives() ) error("the number of derivatives must be the same in all values being dumped"); + for(unsigned i=1; i<nargs; i++) { + (getPntrToArgument(i)->getPntrToAction())->turnOnDerivatives(); + if( npar!=getPntrToArgument(i)->getNumberOfDerivatives() ) error("the number of derivatives must be the same in all values being dumped"); } checkRead(); } -void DumpDerivatives::update(){ +void DumpDerivatives::update() { unsigned npar=getPntrToArgument(0)->getNumberOfDerivatives(); - for(unsigned ipar=0;ipar<npar;ipar++){ + for(unsigned ipar=0; ipar<npar; ipar++) { of.fmtField(" %f"); of.printField("time",getTime()); of.printField("parameter",(int)ipar); - for(unsigned i=0;i<getNumberOfArguments();i++){ + for(unsigned i=0; i<getNumberOfArguments(); i++) { of.fmtField(fmt); of.printField(getPntrToArgument(i)->getName(),getPntrToArgument(i)->getDerivative(ipar) ); } @@ -125,7 +125,7 @@ void DumpDerivatives::update(){ } } -DumpDerivatives::~DumpDerivatives(){ +DumpDerivatives::~DumpDerivatives() { } } diff --git a/src/generic/DumpForces.cpp b/src/generic/DumpForces.cpp index ab96bb070..f5e204d65 100644 --- a/src/generic/DumpForces.cpp +++ b/src/generic/DumpForces.cpp @@ -26,12 +26,12 @@ using namespace std; -namespace PLMD{ -namespace generic{ +namespace PLMD { +namespace generic { //+PLUMEDOC PRINTANALYSIS DUMPFORCES /* -Dump the force acting on one of a values in a file. +Dump the force acting on one of a values in a file. For a CV this command will dump the force on the CV itself. Be aware that in order to have the forces on the atoms @@ -42,7 +42,7 @@ by specifying more than one argument. You can control the buffering of output us \par Examples The following input instructs plumed to write a file called forces that contains -the force acting on the distance between atoms 1 and 2. +the force acting on the distance between atoms 1 and 2. \verbatim DISTANCE ATOM=1,2 LABEL=distance DUMPFORCES ARG=distance STRIDE=1 FILE=forces @@ -54,24 +54,24 @@ DUMPFORCES ARG=distance STRIDE=1 FILE=forces //+ENDPLUMEDOC class DumpForces : -public ActionPilot, -public ActionWithArguments + public ActionPilot, + public ActionWithArguments { string file; string fmt; OFile of; public: - void calculate(){} + void calculate() {} explicit DumpForces(const ActionOptions&); static void registerKeywords(Keywords& keys); - void apply(){} + void apply() {} void update(); ~DumpForces(); }; PLUMED_REGISTER_ACTION(DumpForces,"DUMPFORCES") -void DumpForces::registerKeywords(Keywords& keys){ +void DumpForces::registerKeywords(Keywords& keys) { Action::registerKeywords(keys); ActionPilot::registerKeywords(keys); ActionWithArguments::registerKeywords(keys); @@ -85,10 +85,10 @@ void DumpForces::registerKeywords(Keywords& keys){ } DumpForces::DumpForces(const ActionOptions&ao): -Action(ao), -ActionPilot(ao), -ActionWithArguments(ao), -fmt("%15.10f") + Action(ao), + ActionPilot(ao), + ActionWithArguments(ao), + fmt("%15.10f") { parse("FILE",file); if( file.length()==0 ) error("name of file was not specified"); @@ -103,17 +103,17 @@ fmt("%15.10f") } -void DumpForces::update(){ +void DumpForces::update() { of.fmtField(" %f"); of.printField("time",getTime()); - for(unsigned i=0;i<getNumberOfArguments();i++){ + for(unsigned i=0; i<getNumberOfArguments(); i++) { of.fmtField(fmt); of.printField(getPntrToArgument(i)->getName(),getPntrToArgument(i)->getForce()); } of.printField(); } -DumpForces::~DumpForces(){ +DumpForces::~DumpForces() { } } diff --git a/src/generic/DumpMassCharge.cpp b/src/generic/DumpMassCharge.cpp index f6f4e8392..4153bc838 100644 --- a/src/generic/DumpMassCharge.cpp +++ b/src/generic/DumpMassCharge.cpp @@ -30,7 +30,7 @@ using namespace std; namespace PLMD { -namespace generic{ +namespace generic { //+PLUMEDOC PRINTANALYSIS DUMPMASSCHARGE /* @@ -59,7 +59,7 @@ DUMPMASSCHARGE FILE=mcfile (see also \ref COM and \ref PRINT) In this way, you will be able to use the same masses while processing -a trajectory from the \ref driver . To do so, you need to +a trajectory from the \ref driver . To do so, you need to add the --mc flag on the driver command line, e.g. \verbatim plumed driver --mc mcfile --plumed plumed.dat --ixyz traj.xyz @@ -100,14 +100,14 @@ public: explicit DumpMassCharge(const ActionOptions&); ~DumpMassCharge(); static void registerKeywords( Keywords& keys ); - void calculate(){} - void apply(){} + void calculate() {} + void apply() {} void update(); }; PLUMED_REGISTER_ACTION(DumpMassCharge,"DUMPMASSCHARGE") -void DumpMassCharge::registerKeywords( Keywords& keys ){ +void DumpMassCharge::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionPilot::registerKeywords( keys ); ActionAtomistic::registerKeywords( keys ); @@ -128,8 +128,8 @@ DumpMassCharge::DumpMassCharge(const ActionOptions&ao): parseAtomList("ATOMS",atoms); - if(atoms.size()==0){ - for(unsigned i=0;i<plumed.getAtoms().getNatoms();i++){ + if(atoms.size()==0) { + for(unsigned i=0; i<plumed.getAtoms().getNatoms(); i++) { atoms.push_back(AtomNumber::index(i)); } } @@ -137,20 +137,20 @@ DumpMassCharge::DumpMassCharge(const ActionOptions&ao): checkRead(); log.printf(" printing the following atoms:" ); - for(unsigned i=0;i<atoms.size();++i) log.printf(" %d",atoms[i].serial() ); + for(unsigned i=0; i<atoms.size(); ++i) log.printf(" %d",atoms[i].serial() ); log.printf("\n"); requestAtoms(atoms); } -void DumpMassCharge::update(){ +void DumpMassCharge::update() { if(!first) return; first=false; OFile of; of.link(*this); of.open(file); - - for(int i=0;i<getNumberOfAtoms();i++){ + + for(int i=0; i<getNumberOfAtoms(); i++) { int ii=getAbsoluteIndex(i).index(); of.printField("index",ii); of.printField("mass",getMass(i)); @@ -159,9 +159,9 @@ void DumpMassCharge::update(){ } } -DumpMassCharge::~DumpMassCharge(){ +DumpMassCharge::~DumpMassCharge() { } - + } } diff --git a/src/generic/DumpProjections.cpp b/src/generic/DumpProjections.cpp index 915b68c56..3f0d40429 100644 --- a/src/generic/DumpProjections.cpp +++ b/src/generic/DumpProjections.cpp @@ -27,8 +27,8 @@ using namespace std; -namespace PLMD{ -namespace generic{ +namespace PLMD { +namespace generic { //+PLUMEDOC PRINTANALYSIS DUMPPROJECTIONS /* @@ -50,25 +50,25 @@ DUMPPROJECTIONS ARG=d FILE=proj STRIDE=20 //+ENDPLUMEDOC class DumpProjections : -public ActionPilot, -public ActionWithArguments + public ActionPilot, + public ActionWithArguments { string file; string fmt; OFile of; public: - void calculate(){} + void calculate() {} explicit DumpProjections(const ActionOptions&); static void registerKeywords(Keywords& keys); - void apply(){} + void apply() {} void update(); - bool checkNeedsGradients()const{return true;} + bool checkNeedsGradients()const {return true;} ~DumpProjections(); }; PLUMED_REGISTER_ACTION(DumpProjections,"DUMPPROJECTIONS") -void DumpProjections::registerKeywords(Keywords& keys){ +void DumpProjections::registerKeywords(Keywords& keys) { Action::registerKeywords(keys); ActionPilot::registerKeywords(keys); ActionWithArguments::registerKeywords(keys); @@ -82,10 +82,10 @@ void DumpProjections::registerKeywords(Keywords& keys){ } DumpProjections::DumpProjections(const ActionOptions&ao): -Action(ao), -ActionPilot(ao), -ActionWithArguments(ao), -fmt("%15.10f") + Action(ao), + ActionPilot(ao), + ActionWithArguments(ao), + fmt("%15.10f") { parse("FILE",file); if( file.length()==0 ) error("filename not specified"); @@ -96,16 +96,16 @@ fmt("%15.10f") log.printf(" with format %s\n",fmt.c_str()); checkRead(); - for(unsigned i=0;i<getNumberOfArguments();++i){ - (getPntrToArgument(i)->getPntrToAction())->turnOnDerivatives(); + for(unsigned i=0; i<getNumberOfArguments(); ++i) { + (getPntrToArgument(i)->getPntrToAction())->turnOnDerivatives(); } } -void DumpProjections::update(){ +void DumpProjections::update() { of.fmtField(" %f").printField("time",getTime()); - for(unsigned i=0;i<getNumberOfArguments();i++){ - for(unsigned j=0;j<getNumberOfArguments();j++){ + for(unsigned i=0; i<getNumberOfArguments(); i++) { + for(unsigned j=0; j<getNumberOfArguments(); j++) { of.fmtField(fmt); of.printField(getPntrToArgument(i)->getName()+"-"+getPntrToArgument(j)->getName(),getProjection(i,j)); } @@ -113,7 +113,7 @@ void DumpProjections::update(){ of.printField(); } -DumpProjections::~DumpProjections(){ +DumpProjections::~DumpProjections() { } } diff --git a/src/generic/EffectiveEnergyDrift.cpp b/src/generic/EffectiveEnergyDrift.cpp index 885491e2b..1c3961390 100644 --- a/src/generic/EffectiveEnergyDrift.cpp +++ b/src/generic/EffectiveEnergyDrift.cpp @@ -20,7 +20,7 @@ along with plumed. If not, see <http://www.gnu.org/licenses/>. +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ -/* +/* This class was originally written by Marco Jacopo Ferrarotti (marco.ferrarotti@gmail.com) and Giovanni Bussi */ @@ -42,7 +42,7 @@ using namespace std; namespace PLMD { -namespace generic{ +namespace generic { //+PLUMEDOC GENERIC EFFECTIVE_ENERGY_DRIFT /* @@ -57,7 +57,7 @@ simulation on the Debye-Huckel energy. Since this variable is very expensive, it could be conveniently computed every second step. \verbatim dh: DHENERGY GROUPA=1-10 GROUPB=11-20 EPSILON=80.0 I=0.1 TEMP=300.0 -METAD ARG=dh HEIGHT=0.5 SIGMA=0.1 PACE=500 STRIDE=2 +METAD ARG=dh HEIGHT=0.5 SIGMA=0.1 PACE=500 STRIDE=2 EFFECTIVE_ENERGY_DRIFT PRINT_STRIDE=100 FILE=eff \endverbatim @@ -73,7 +73,7 @@ EFFECTIVE_ENERGY_DRIFT PRINT_STRIDE=100 FILE=eff class EffectiveEnergyDrift: -public ActionPilot{ + public ActionPilot { OFile output; long int printStride; @@ -115,14 +115,14 @@ public: static void registerKeywords( Keywords& keys ); - void calculate(){}; - void apply(){}; + void calculate() {}; + void apply() {}; void update(); }; PLUMED_REGISTER_ACTION(EffectiveEnergyDrift,"EFFECTIVE_ENERGY_DRIFT") -void EffectiveEnergyDrift::registerKeywords( Keywords& keys ){ +void EffectiveEnergyDrift::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionPilot::registerKeywords( keys ); @@ -136,14 +136,14 @@ void EffectiveEnergyDrift::registerKeywords( Keywords& keys ){ } EffectiveEnergyDrift::EffectiveEnergyDrift(const ActionOptions&ao): -Action(ao), -ActionPilot(ao), -eed(0.0), -atoms(plumed.getAtoms()), -nProc(plumed.comm.Get_size()), -initialBias(0.0), -isFirstStep(true), -ensemble(false) + Action(ao), + ActionPilot(ao), + eed(0.0), + atoms(plumed.getAtoms()), + nProc(plumed.comm.Get_size()), + initialBias(0.0), + isFirstStep(true), + ensemble(false) { //stride must be == 1 if(getStride()!=1) error("EFFECTIVE_ENERGY_DRIFT must have STRIDE=1 to work properly"); @@ -163,13 +163,13 @@ ensemble(false) parseFlag("ENSEMBLE",ensemble); if(ensemble&&comm.Get_rank()==0) { if(multi_sim_comm.Get_size()<2) error("You CANNOT run Replica-Averaged simulations without running multiple replicas!\n"); - } + } log<<"Bibliography "<<cite("Ferrarotti, Bottaro, Perez-Villa, and Bussi, submitted (2014)")<<"\n"; //construct biases from ActionWithValue with a component named bias vector<ActionWithValue*> tmpActions=plumed.getActionSet().select<ActionWithValue*>(); - for(unsigned i=0;i<tmpActions.size();i++) if(tmpActions[i]->exists(tmpActions[i]->getLabel()+".bias")) biases.push_back(tmpActions[i]); + for(unsigned i=0; i<tmpActions.size(); i++) if(tmpActions[i]->exists(tmpActions[i]->getLabel()+".bias")) biases.push_back(tmpActions[i]); //resize counters and displacements useful to communicate with MPI_Allgatherv indexCnt.resize(nProc); @@ -182,11 +182,11 @@ ensemble(false) backmap.resize(atoms.getNatoms()); } -EffectiveEnergyDrift::~EffectiveEnergyDrift(){ +EffectiveEnergyDrift::~EffectiveEnergyDrift() { } -void EffectiveEnergyDrift::update(){ +void EffectiveEnergyDrift::update() { bool pbc=atoms.getPbc().isSet(); //retrive data of local atoms @@ -194,11 +194,11 @@ void EffectiveEnergyDrift::update(){ nLocalAtoms = gatindex.size(); atoms.getLocalPositions(positions); atoms.getLocalForces(forces); - if(pbc){ + if(pbc) { Tensor B=atoms.getPbc().getBox(); Tensor IB=atoms.getPbc().getInvBox(); -#pragma omp parallel for - for(unsigned i=0;i<positions.size();++i){ + #pragma omp parallel for + for(unsigned i=0; i<positions.size(); ++i) { positions[i]=matmul(positions[i],IB); forces[i]=matmul(B,forces[i]); } @@ -207,7 +207,7 @@ void EffectiveEnergyDrift::update(){ } //init stored data at the first step - if(isFirstStep){ + if(isFirstStep) { pDdStep=0; pGatindex = atoms.getGatindex(); pNLocalAtoms = pGatindex.size(); @@ -218,17 +218,17 @@ void EffectiveEnergyDrift::update(){ pbox=box; pfbox=fbox; initialBias=plumed.getBias(); - + isFirstStep=false; } //if the dd has changed we have to reshare the stored data - if(pDdStep<atoms.getDdStep() && nLocalAtoms<atoms.getNatoms()){ + if(pDdStep<atoms.getDdStep() && nLocalAtoms<atoms.getNatoms()) { //prepare the data to be sent indexS.resize(pNLocalAtoms); dataS.resize(pNLocalAtoms*6); - for(int i=0; i<pNLocalAtoms; i++){ + for(int i=0; i<pNLocalAtoms; i++) { indexS[i] = pGatindex[i]; dataS[i*6] = pPositions[i][0]; dataS[i*6+1] = pPositions[i][1]; @@ -241,7 +241,7 @@ void EffectiveEnergyDrift::update(){ //setup the counters and displacements for the communication plumed.comm.Allgather(&pNLocalAtoms,1,&indexCnt[0],1); indexDsp[0] = 0; - for(int i=0; i<nProc; i++){ + for(int i=0; i<nProc; i++) { dataCnt[i] = indexCnt[i]*6; if(i+1<nProc) indexDsp[i+1] = indexDsp[i]+indexCnt[i]; @@ -258,10 +258,10 @@ void EffectiveEnergyDrift::update(){ pForces.resize(nLocalAtoms); //compute backmap - for(unsigned j=0;j<indexR.size();j++) backmap[indexR[j]]=j; + for(unsigned j=0; j<indexR.size(); j++) backmap[indexR[j]]=j; //fill the vectors pGatindex, pPositions and pForces - for(int i=0; i<nLocalAtoms; i++){ + for(int i=0; i<nLocalAtoms; i++) { int glb=backmap[gatindex[i]]; pGatindex[i] = indexR[glb]; pPositions[i][0] = dataR[glb*6]; @@ -274,34 +274,34 @@ void EffectiveEnergyDrift::update(){ } //compute the effective energy drift on local atoms - + double eed_tmp=eed; -#pragma omp parallel for reduction(+:eed_tmp) - for(int i=0;i<nLocalAtoms;i++){ + #pragma omp parallel for reduction(+:eed_tmp) + for(int i=0; i<nLocalAtoms; i++) { Vector dst=delta(pPositions[i],positions[i]); - if(pbc) for(unsigned k=0;k<3;k++) dst[k]=Tools::pbc(dst[k]); + if(pbc) for(unsigned k=0; k<3; k++) dst[k]=Tools::pbc(dst[k]); eed_tmp += dotProduct(dst, forces[i]+pForces[i])*0.5; } eed=eed_tmp; - if(plumed.comm.Get_rank()==0){ - for(unsigned i=0;i<3;i++) for(unsigned j=0;j<3;j++) - eed-=0.5*(pfbox(i,j)+fbox(i,j))*(box(i,j)-pbox(i,j)); + if(plumed.comm.Get_rank()==0) { + for(unsigned i=0; i<3; i++) for(unsigned j=0; j<3; j++) + eed-=0.5*(pfbox(i,j)+fbox(i,j))*(box(i,j)-pbox(i,j)); } //print the effective energy drift on FILE with frequency PRINT_STRIDE - if(plumed.getStep()%printStride==0){ + if(plumed.getStep()%printStride==0) { double eedSum = eed; double bias = 0.0; //we cannot just use plumed.getBias() because it will be ==0.0 if PRINT_STRIDE //is not a multiple of the bias actions stride - for(unsigned i=0;i<biases.size();i++) bias+=biases[i]->getOutputQuantity("bias"); + for(unsigned i=0; i<biases.size(); i++) bias+=biases[i]->getOutputQuantity("bias"); plumed.comm.Sum(&eedSum,1); - + double effective = eedSum+bias-initialBias-plumed.getWork(); // this is to take into account ensemble averaging if(ensemble) { diff --git a/src/generic/FitToTemplate.cpp b/src/generic/FitToTemplate.cpp index ad35b40b7..37e38333f 100644 --- a/src/generic/FitToTemplate.cpp +++ b/src/generic/FitToTemplate.cpp @@ -41,7 +41,7 @@ using namespace std; namespace PLMD { -namespace generic{ +namespace generic { //+PLUMEDOC GENERIC FIT_TO_TEMPLATE /* @@ -65,7 +65,7 @@ change the result. Examples are: \attention The implementation of TYPE=OPTIMAL is available but should be considered in testing phase. Please report any -strange behavior. +strange behavior. \attention This directive modifies the stored position at the precise moment @@ -104,7 +104,7 @@ class FitToTemplate: Vector center; Vector shift; // optimal alignment related stuff - PLMD::RMSD* rmsd; + PLMD::RMSD* rmsd; Tensor rotation; Matrix< std::vector<Vector> > drotdpos; std::vector<Vector> positions; @@ -113,19 +113,19 @@ class FitToTemplate: std::vector<Vector> centeredpositions; Vector center_positions; - + public: explicit FitToTemplate(const ActionOptions&ao); ~FitToTemplate(); static void registerKeywords( Keywords& keys ); void calculate(); void apply(); - unsigned getNumberOfDerivatives(){plumed_merror("You should not call this function");}; + unsigned getNumberOfDerivatives() {plumed_merror("You should not call this function");}; }; PLUMED_REGISTER_ACTION(FitToTemplate,"FIT_TO_TEMPLATE") -void FitToTemplate::registerKeywords( Keywords& keys ){ +void FitToTemplate::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionAtomistic::registerKeywords( keys ); keys.add("compulsory","STRIDE","1","the frequency with which molecules are reassembled. Unless you are completely certain about what you are doing leave this set equal to 1!"); @@ -134,18 +134,18 @@ void FitToTemplate::registerKeywords( Keywords& keys ){ } FitToTemplate::FitToTemplate(const ActionOptions&ao): -Action(ao), -ActionPilot(ao), -ActionAtomistic(ao), -ActionWithValue(ao), -rmsd(NULL) + Action(ao), + ActionPilot(ao), + ActionAtomistic(ao), + ActionWithValue(ao), + rmsd(NULL) { string reference; parse("REFERENCE",reference); type.assign("SIMPLE"); parse("TYPE",type); - // if(type!="SIMPLE") error("Only TYPE=SIMPLE is implemented in FIT_TO_TEMPLATE"); +// if(type!="SIMPLE") error("Only TYPE=SIMPLE is implemented in FIT_TO_TEMPLATE"); checkRead(); @@ -153,7 +153,7 @@ rmsd(NULL) // read everything in ang and transform to nm if we are not in natural units if( !pdb.read(reference,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength()) ) - error("missing input file " + reference ); + error("missing input file " + reference ); requestAtoms(pdb.getAtomNumbers()); @@ -163,22 +163,22 @@ rmsd(NULL) // normalize weights - double n=0.0; for(unsigned i=0;i<weights.size();++i) n+=weights[i]; n=1.0/n; - for(unsigned i=0;i<weights.size();++i) weights[i]*=n; + double n=0.0; for(unsigned i=0; i<weights.size(); ++i) n+=weights[i]; n=1.0/n; + for(unsigned i=0; i<weights.size(); ++i) weights[i]*=n; // normalize weights for rmsd calculation vector<double> weights_measure=pdb.getBeta(); - n=0.0; for(unsigned i=0;i<weights_measure.size();++i) n+=weights_measure[i]; n=1.0/n; - for(unsigned i=0;i<weights_measure.size();++i) weights_measure[i]*=n; + n=0.0; for(unsigned i=0; i<weights_measure.size(); ++i) n+=weights_measure[i]; n=1.0/n; + for(unsigned i=0; i<weights_measure.size(); ++i) weights_measure[i]*=n; - // subtract the center - for(unsigned i=0;i<weights.size();++i) center+=positions[i]*weights[i]; - for(unsigned i=0;i<weights.size();++i) positions[i]-=center; + // subtract the center + for(unsigned i=0; i<weights.size(); ++i) center+=positions[i]*weights[i]; + for(unsigned i=0; i<weights.size(); ++i) positions[i]-=center; - if(type=="OPTIMAL" or type=="OPTIMAL-FAST" ){ - rmsd=new RMSD(); - rmsd->set(weights,weights_measure,positions,type,false,false);// note: the reference is shifted now with center in the origin - log<<" Method chosen for fitting: "<<rmsd->getMethod()<<" \n"; + if(type=="OPTIMAL" or type=="OPTIMAL-FAST" ) { + rmsd=new RMSD(); + rmsd->set(weights,weights_measure,positions,type,false,false);// note: the reference is shifted now with center in the origin + log<<" Method chosen for fitting: "<<rmsd->getMethod()<<" \n"; } // register the value of rmsd (might be useful sometimes) addValue(); setNotPeriodic(); @@ -191,92 +191,92 @@ rmsd(NULL) } -void FitToTemplate::calculate(){ +void FitToTemplate::calculate() { - Vector cc; + Vector cc; - for(unsigned i=0;i<aligned.size();++i){ - cc+=weights[i]*modifyPosition(aligned[i]); - } + for(unsigned i=0; i<aligned.size(); ++i) { + cc+=weights[i]*modifyPosition(aligned[i]); + } - if (type=="SIMPLE"){ - shift=center-cc; - setValue(shift.modulo()); - for(unsigned i=0;i<getTotAtoms();i++){ - Vector & ato (modifyPosition(AtomNumber::index(i))); - ato+=shift; - } - } - else if( type=="OPTIMAL" or type=="OPTIMAL-FAST"){ + if (type=="SIMPLE") { + shift=center-cc; + setValue(shift.modulo()); + for(unsigned i=0; i<getTotAtoms(); i++) { + Vector & ato (modifyPosition(AtomNumber::index(i))); + ato+=shift; + } + } + else if( type=="OPTIMAL" or type=="OPTIMAL-FAST") { // we store positions here to be used in apply() // notice that in apply() it is not guaranteed that positions are still equal to their value here // since they could have been changed by a subsequent FIT_TO_TEMPLATE - positions.resize(aligned.size()); - for (unsigned i=0;i<aligned.size();i++) positions[i]=modifyPosition(aligned[i]); - - // specific stuff that provides all that is needed - double r=rmsd->calc_FitElements( positions, rotation , drotdpos , centeredpositions, center_positions); - setValue(r); - for(unsigned i=0;i<getTotAtoms();i++){ - Vector & ato (modifyPosition(AtomNumber::index(i))); - ato=matmul(rotation,ato-center_positions)+center; - } + positions.resize(aligned.size()); + for (unsigned i=0; i<aligned.size(); i++) positions[i]=modifyPosition(aligned[i]); + + // specific stuff that provides all that is needed + double r=rmsd->calc_FitElements( positions, rotation, drotdpos, centeredpositions, center_positions); + setValue(r); + for(unsigned i=0; i<getTotAtoms(); i++) { + Vector & ato (modifyPosition(AtomNumber::index(i))); + ato=matmul(rotation,ato-center_positions)+center; + } // rotate box - Pbc & pbc(modifyGlobalPbc()); - pbc.setBox(matmul(pbc.getBox(),transpose(rotation))); - } + Pbc & pbc(modifyGlobalPbc()); + pbc.setBox(matmul(pbc.getBox(),transpose(rotation))); + } } -void FitToTemplate::apply(){ +void FitToTemplate::apply() { if (type=="SIMPLE") { - Vector totForce; - for(unsigned i=0;i<getTotAtoms();i++){ - totForce+=modifyGlobalForce(AtomNumber::index(i)); - } - Tensor & vv(modifyGlobalVirial()); - vv+=Tensor(center,totForce); - for(unsigned i=0;i<aligned.size();++i){ - Vector & ff(modifyGlobalForce(aligned[i])); - ff-=totForce*weights[i]; - } - } else if ( type=="OPTIMAL" or type=="OPTIMAL-FAST") { - Vector totForce; - for(unsigned i=0;i<getTotAtoms(); i++) { - Vector & f(modifyGlobalForce(AtomNumber::index(i))); + Vector totForce; + for(unsigned i=0; i<getTotAtoms(); i++) { + totForce+=modifyGlobalForce(AtomNumber::index(i)); + } + Tensor & vv(modifyGlobalVirial()); + vv+=Tensor(center,totForce); + for(unsigned i=0; i<aligned.size(); ++i) { + Vector & ff(modifyGlobalForce(aligned[i])); + ff-=totForce*weights[i]; + } + } else if ( type=="OPTIMAL" or type=="OPTIMAL-FAST") { + Vector totForce; + for(unsigned i=0; i<getTotAtoms(); i++) { + Vector & f(modifyGlobalForce(AtomNumber::index(i))); // rotate back forces - f=matmul(transpose(rotation),f); + f=matmul(transpose(rotation),f); // accumulate rotated c.o.m. forces - this is already in the non rotated reference frame - totForce+=f; - } - Tensor& virial(modifyGlobalVirial()); + totForce+=f; + } + Tensor& virial(modifyGlobalVirial()); // notice that an extra Tensor(center,matmul(rotation,totForce)) is required to // compute the derivatives of the rotation with respect to center - Tensor ww=matmul(transpose(rotation),virial+Tensor(center,matmul(rotation,totForce))); + Tensor ww=matmul(transpose(rotation),virial+Tensor(center,matmul(rotation,totForce))); // rotate back virial - virial=matmul(transpose(rotation),matmul(virial,rotation)); + virial=matmul(transpose(rotation),matmul(virial,rotation)); // now we compute the force due to alignment - for(unsigned i=0;i<aligned.size(); i++) { - Vector g; - for(unsigned k=0;k<3;k++){ + for(unsigned i=0; i<aligned.size(); i++) { + Vector g; + for(unsigned k=0; k<3; k++) { // this could be made faster computing only the diagonal of d - Tensor d=matmul(ww,RMSD::getMatrixFromDRot(drotdpos,i,k)); - g[k]=(d(0,0)+d(1,1)+d(2,2)); - } + Tensor d=matmul(ww,RMSD::getMatrixFromDRot(drotdpos,i,k)); + g[k]=(d(0,0)+d(1,1)+d(2,2)); + } // here is the extra contribution - modifyGlobalForce(aligned[i])+=-g-weights[i]*totForce; + modifyGlobalForce(aligned[i])+=-g-weights[i]*totForce; // here it the contribution to the virial // notice that here we can use absolute positions since, for the alignment to be defined, // positions should be in one well defined periodic image - virial+=extProduct(positions[i],g); - } + virial+=extProduct(positions[i],g); + } // finally, correction to the virial - virial+=extProduct(matmul(transpose(rotation),center),totForce); + virial+=extProduct(matmul(transpose(rotation),center),totForce); } } -FitToTemplate::~FitToTemplate(){ +FitToTemplate::~FitToTemplate() { if(rmsd) delete rmsd; } diff --git a/src/generic/Flush.cpp b/src/generic/Flush.cpp index 7af0a4917..78c00f87d 100644 --- a/src/generic/Flush.cpp +++ b/src/generic/Flush.cpp @@ -24,8 +24,8 @@ #include "core/PlumedMain.h" #include "core/ActionSet.h" -namespace PLMD{ -namespace generic{ +namespace PLMD { +namespace generic { using namespace std; @@ -36,7 +36,7 @@ Notice that all files are flushed anyway every 10000 steps. This is useful for preventing data loss that would otherwise arrise as a consequence of the code -storing data for printing in the buffers. Notice that wherever it is written in the +storing data for printing in the buffers. Notice that wherever it is written in the plumed input file, it will flush all the open files. \par Examples @@ -66,20 +66,20 @@ public: checkRead(); } static void registerKeywords( Keywords& keys ); - void calculate(){} - void apply(){} - void update(){ + void calculate() {} + void apply() {} + void update() { plumed.fflush(); log.flush(); const ActionSet & actionSet(plumed.getActionSet()); for(const auto & p : actionSet) - p->fflush(); + p->fflush(); } }; PLUMED_REGISTER_ACTION(Flush,"FLUSH") -void Flush::registerKeywords( Keywords& keys ){ +void Flush::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionPilot::registerKeywords( keys ); keys.add("compulsory","STRIDE","the frequency with which all the open files should be flushed"); diff --git a/src/generic/Group.cpp b/src/generic/Group.cpp index a214aa353..0403d6b76 100644 --- a/src/generic/Group.cpp +++ b/src/generic/Group.cpp @@ -31,19 +31,19 @@ using namespace std; -namespace PLMD{ -namespace generic{ +namespace PLMD { +namespace generic { //+PLUMEDOC GENERIC GROUP /* Define a group of atoms so that a particular list of atoms can be referenced with a single label -in definitions of CVs or virtual atoms. +in definitions of CVs or virtual atoms. Atoms can be listed as comma separated numbers (i.e. 1,2,3,10,45,7,9,..) , simple positive ranges (i.e. 20-40), ranges with a stride either positive or negative (i.e. 20-40:2 or 80-50:-2) or as -combinations of all the former methods (1,2,4,5,10-20,21-40:2,80-50:-2). +combinations of all the former methods (1,2,4,5,10-20,21-40:2,80-50:-2). -Moreover, lists can be imported from ndx files (GROMACS format). Use NDX_FILE to set the name of +Moreover, lists can be imported from ndx files (GROMACS format). Use NDX_FILE to set the name of the index file and NDX_GROUP to set the name of the group to be imported (default is first one). It is also possible to remove atoms from a list and or sort them using keywords REMOVE, SORT, and UNIQUE. @@ -126,8 +126,8 @@ public: explicit Group(const ActionOptions&ao); ~Group(); static void registerKeywords( Keywords& keys ); - void calculate(){} - void apply(){} + void calculate() {} + void apply() {} }; PLUMED_REGISTER_ACTION(Group,"GROUP") @@ -144,25 +144,25 @@ Group::Group(const ActionOptions&ao): if(ndxfile.length()>0 && atoms.size()>0) error("either use explicit atom list or import from index file"); if(ndxfile.length()==0 && ndxgroup.size()>0) error("NDX_GROUP can be only used is NDX_FILE is also used"); - if(ndxfile.length()>0){ + if(ndxfile.length()>0) { if(ndxgroup.size()>0) log<<" importing group '"+ndxgroup+"'"; else log<<" importing first group"; log<<" from index file "<<ndxfile<<"\n"; - + IFile ifile; ifile.open(ndxfile); std::string line; std::string groupname; bool firstgroup=true; bool groupfound=false; - while(ifile.getline(line)){ + while(ifile.getline(line)) { std::vector<std::string> words=Tools::getWords(line); - if(words.size()>=3 && words[0]=="[" && words[2]=="]"){ + if(words.size()>=3 && words[0]=="[" && words[2]=="]") { if(groupname.length()>0) firstgroup=false; groupname=words[1]; if(groupname==ndxgroup || ndxgroup.length()==0) groupfound=true; - } else if(groupname==ndxgroup || (firstgroup && ndxgroup.length()==0)){ - for(unsigned i=0;i<words.size();i++){ + } else if(groupname==ndxgroup || (firstgroup && ndxgroup.length()==0)) { + for(unsigned i=0; i<words.size(); i++) { AtomNumber at; Tools::convert(words[i],at); atoms.push_back(at); } @@ -173,44 +173,44 @@ Group::Group(const ActionOptions&ao): std::vector<AtomNumber> remove; parseAtomList("REMOVE",remove); - if(remove.size()>0){ + if(remove.size()>0) { std::vector<AtomNumber> notfound; log<<" removing these atoms from the list:"; - for(unsigned i=0;i<remove.size();i++){ + for(unsigned i=0; i<remove.size(); i++) { const auto it = find(atoms.begin(),atoms.end(),remove[i]); - if(it!=atoms.end()){ + if(it!=atoms.end()) { log<<" "<<(*it).serial(); atoms.erase(it); } else notfound.push_back(remove[i]); } log<<"\n"; - if(notfound.size()>0){ + if(notfound.size()>0) { log<<" the following atoms were not found:"; - for(unsigned i=0;i<notfound.size();i++) log<<" "<<notfound[i].serial(); + for(unsigned i=0; i<notfound.size(); i++) log<<" "<<notfound[i].serial(); log<<"\n"; } } bool sortme=false; parseFlag("SORT",sortme); - if(sortme){ + if(sortme) { log<<" atoms are sorted\n"; sort(atoms.begin(),atoms.end()); } bool unique=false; parseFlag("UNIQUE",unique); - if(unique){ + if(unique) { log<<" sorting atoms and removing duplicates\n"; Tools::removeDuplicates(atoms); } this->atoms.insertGroup(getLabel(),atoms); log.printf(" list of atoms "); - for(unsigned i=0;i<atoms.size();i++) log<<" "<<atoms[i].serial(); + for(unsigned i=0; i<atoms.size(); i++) log<<" "<<atoms[i].serial(); log.printf("\n"); } -void Group::registerKeywords( Keywords& keys ){ +void Group::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionAtomistic::registerKeywords( keys ); keys.add("atoms", "ATOMS", "the numerical indexes for the set of atoms in the group"); @@ -221,7 +221,7 @@ void Group::registerKeywords( Keywords& keys ){ keys.add("optional", "NDX_GROUP", "the name of the group to be imported (gromacs syntax) - first group found is used by default"); } -Group::~Group(){ +Group::~Group() { atoms.removeGroup(getLabel()); } diff --git a/src/generic/Include.cpp b/src/generic/Include.cpp index 93e8077a9..664c84ba6 100644 --- a/src/generic/Include.cpp +++ b/src/generic/Include.cpp @@ -26,8 +26,8 @@ using namespace std; -namespace PLMD{ -namespace generic{ +namespace PLMD { +namespace generic { //+PLUMEDOC GENERIC INCLUDE /* @@ -69,19 +69,19 @@ class Include : public: static void registerKeywords( Keywords& keys ); explicit Include(const ActionOptions&ao); - void calculate(){} - void apply(){} + void calculate() {} + void apply() {} }; PLUMED_REGISTER_ACTION(Include,"INCLUDE") -void Include::registerKeywords( Keywords& keys ){ +void Include::registerKeywords( Keywords& keys ) { Action::registerKeywords(keys); keys.add("compulsory","FILE","file to be included"); } Include::Include(const ActionOptions&ao): -Action(ao) + Action(ao) { std::string f; parse("FILE",f); diff --git a/src/generic/Print.cpp b/src/generic/Print.cpp index 9adce6b40..2a87d1f7b 100644 --- a/src/generic/Print.cpp +++ b/src/generic/Print.cpp @@ -25,19 +25,19 @@ using namespace std; -namespace PLMD{ -namespace generic{ +namespace PLMD { +namespace generic { //+PLUMEDOC PRINTANALYSIS PRINT /* Print quantities to a file. This directive can be used multiple times -in the input so you can print files with different strides or print different quantities +in the input so you can print files with different strides or print different quantities to different files. You can control the buffering of output using the \subpage FLUSH keyword. \par Examples -The following input instructs plumed to print the distance between atoms 3 and 5 on a file +The following input instructs plumed to print the distance between atoms 3 and 5 on a file called COLVAR every 10 steps, and the distance and total energy on a file called COLVAR_ALL every 1000 steps. \verbatim @@ -52,8 +52,8 @@ PRINT ARG=distance,energy STRIDE=1000 FILE=COLVAR_ALL //+ENDPLUMEDOC class Print : -public ActionPilot, -public ActionWithArguments + public ActionPilot, + public ActionWithArguments { string file; OFile ofile; @@ -69,18 +69,18 @@ public ActionWithArguments vector<Value*> rotateArguments; ///////////////////////////////////////// public: - void calculate(){} + void calculate() {} void prepare(); explicit Print(const ActionOptions&); static void registerKeywords(Keywords& keys); - void apply(){} + void apply() {} void update(); ~Print(); }; PLUMED_REGISTER_ACTION(Print,"PRINT") -void Print::registerKeywords(Keywords& keys){ +void Print::registerKeywords(Keywords& keys) { Action::registerKeywords(keys); ActionPilot::registerKeywords(keys); ActionWithArguments::registerKeywords(keys); @@ -95,15 +95,15 @@ void Print::registerKeywords(Keywords& keys){ } Print::Print(const ActionOptions&ao): -Action(ao), -ActionPilot(ao), -ActionWithArguments(ao), -fmt("%f"), -rotate(0) + Action(ao), + ActionPilot(ao), + ActionWithArguments(ao), + fmt("%f"), + rotate(0) { ofile.link(*this); parse("FILE",file); - if(file.length()>0){ + if(file.length()>0) { ofile.open(file); log.printf(" on file %s\n",file.c_str()); } else { @@ -113,15 +113,15 @@ rotate(0) parse("FMT",fmt); fmt=" "+fmt; log.printf(" with format %s\n",fmt.c_str()); - for(unsigned i=0;i<getNumberOfArguments();++i) ofile.setupPrintValue( getPntrToArgument(i) ); + for(unsigned i=0; i<getNumberOfArguments(); ++i) ofile.setupPrintValue( getPntrToArgument(i) ); ///////////////////////////////////////// // these are crazy things just for debug: // they allow to change regularly the // printed argument parse("_ROTATE",rotate); - if(rotate>0){ + if(rotate>0) { rotateCountdown=rotate; - for(unsigned i=0;i<getNumberOfArguments();++i) rotateArguments.push_back( getPntrToArgument(i) ); + for(unsigned i=0; i<getNumberOfArguments(); ++i) rotateArguments.push_back( getPntrToArgument(i) ); vector<Value*> a(1,rotateArguments[0]); requestArguments(vector<Value*>(1,rotateArguments[0])); rotateLast=0; @@ -130,14 +130,14 @@ rotate(0) checkRead(); } -void Print::prepare(){ +void Print::prepare() { ///////////////////////////////////////// // these are crazy things just for debug: // they allow to change regularly the // printed argument - if(rotate>0){ + if(rotate>0) { rotateCountdown--; - if(rotateCountdown==0){ + if(rotateCountdown==0) { rotateCountdown=rotate; rotateLast++; rotateLast%=rotateArguments.size(); @@ -147,18 +147,18 @@ void Print::prepare(){ ///////////////////////////////////////// } -void Print::update(){ - ofile.fmtField(" %f"); - ofile.printField("time",getTime()); - for(unsigned i=0;i<getNumberOfArguments();i++){ - ofile.fmtField(fmt); - ofile.printField( getPntrToArgument(i), getArgument(i) ); - //ofile.printField(getPntrToArgument(i)->getName(),getArgument(i)); - } - ofile.printField(); +void Print::update() { + ofile.fmtField(" %f"); + ofile.printField("time",getTime()); + for(unsigned i=0; i<getNumberOfArguments(); i++) { + ofile.fmtField(fmt); + ofile.printField( getPntrToArgument(i), getArgument(i) ); + //ofile.printField(getPntrToArgument(i)->getName(),getArgument(i)); + } + ofile.printField(); } -Print::~Print(){ +Print::~Print() { } } diff --git a/src/generic/RandomExchanges.cpp b/src/generic/RandomExchanges.cpp index b98889e2f..be36873bc 100644 --- a/src/generic/RandomExchanges.cpp +++ b/src/generic/RandomExchanges.cpp @@ -27,8 +27,8 @@ using namespace std; -namespace PLMD{ -namespace generic{ +namespace PLMD { +namespace generic { //+PLUMEDOC GENERIC RANDOM_EXCHANGES /* @@ -78,19 +78,19 @@ class RandomExchanges: public: static void registerKeywords( Keywords& keys ); explicit RandomExchanges(const ActionOptions&ao); - void calculate(){} - void apply(){} + void calculate() {} + void apply() {} }; PLUMED_REGISTER_ACTION(RandomExchanges,"RANDOM_EXCHANGES") -void RandomExchanges::registerKeywords( Keywords& keys ){ +void RandomExchanges::registerKeywords( Keywords& keys ) { Action::registerKeywords(keys); keys.add("optional","SEED","seed for random exchanges"); } RandomExchanges::RandomExchanges(const ActionOptions&ao): -Action(ao) + Action(ao) { plumed.getExchangePatterns().setFlag(ExchangePatterns::RANDOM); // I convert the seed to -seed because I think it is more general to use a positive seed in input diff --git a/src/generic/Read.cpp b/src/generic/Read.cpp index 2b67c1685..88c279630 100644 --- a/src/generic/Read.cpp +++ b/src/generic/Read.cpp @@ -27,20 +27,20 @@ #include "core/Atoms.h" #include "tools/IFile.h" -namespace PLMD{ -namespace generic{ +namespace PLMD { +namespace generic { //+PLUMEDOC GENERIC READ -/* +/* Read quantities from a colvar file. -This Action can be used with driver to read in a colvar file that was generated during +This Action can be used with driver to read in a colvar file that was generated during an MD simulation \par Description of components The READ command will read those fields that are labelled with the text string given to the -VALUE keyword. It will also read in any fields that are labelleled with the text string +VALUE keyword. It will also read in any fields that are labelleled with the text string given to the VALUE keyword followed by a dot and a further string. If a single Value is read in this value can be referenced using the label of the Action. Alternatively, if multiple quanties are read in, they can be referenced elsewhere in the input by using the label for the Action @@ -49,7 +49,7 @@ followed by a dot and the character string that appeared after the dot in the ti \par Examples This input reads in data from a file called input_colvar.data that was generated -in a calculation that involved PLUMED. The first command reads in the data from the +in a calculation that involved PLUMED. The first command reads in the data from the column headed phi1 while the second reads in the data from the column headed phi2. \verbatim @@ -62,8 +62,8 @@ PRINT ARG=rphi1,rphi2 STRIDE=500 FILE=output_colvar.data //+ENDPLUMEDOC class Read : -public ActionPilot, -public ActionWithValue + public ActionPilot, + public ActionWithValue { private: bool ignore_time; @@ -78,7 +78,7 @@ public: explicit Read(const ActionOptions&); ~Read(); void prepare(); - void apply(){} + void apply() {} void calculate(); void update(); std::string getFilename() const; @@ -89,7 +89,7 @@ public: PLUMED_REGISTER_ACTION(Read,"READ") -void Read::registerKeywords(Keywords& keys){ +void Read::registerKeywords(Keywords& keys) { Action::registerKeywords(keys); ActionPilot::registerKeywords(keys); ActionWithValue::registerKeywords(keys); @@ -98,9 +98,9 @@ void Read::registerKeywords(Keywords& keys){ keys.add("compulsory","VALUES","the values to read from the file"); keys.add("compulsory","FILE","the name of the file from which to read these quantities"); keys.addFlag("IGNORE_TIME",false,"ignore the time in the colvar file. When this flag is not present read will be quite strict " - "about the start time of the simulation and the stride between frames"); + "about the start time of the simulation and the stride between frames"); keys.addFlag("IGNORE_FORCES",false,"use this flag if the forces added by any bias can be safely ignored. As an example forces can be " - "safely ignored if you are doing postprocessing that does not involve outputting forces"); + "safely ignored if you are doing postprocessing that does not involve outputting forces"); keys.remove("NUMERICAL_DERIVATIVES"); keys.use("UPDATE_FROM"); keys.use("UPDATE_UNTIL"); @@ -108,12 +108,12 @@ void Read::registerKeywords(Keywords& keys){ } Read::Read(const ActionOptions&ao): -Action(ao), -ActionPilot(ao), -ActionWithValue(ao), -ignore_time(false), -ignore_forces(false), -nlinesPerStep(1) + Action(ao), + ActionPilot(ao), + ActionWithValue(ao), + ignore_time(false), + ignore_forces(false), + nlinesPerStep(1) { // Read the file name from the input line parse("FILE",filename); @@ -124,18 +124,18 @@ nlinesPerStep(1) // Open the file if it is not already opened cloned_file=false; std::vector<Read*> other_reads=plumed.getActionSet().select<Read*>(); - for(unsigned i=0;i<other_reads.size();++i){ - if( other_reads[i]->getFilename()==filename ){ - ifile=other_reads[i]->getFile(); - cloned_file=true; - } + for(unsigned i=0; i<other_reads.size(); ++i) { + if( other_reads[i]->getFilename()==filename ) { + ifile=other_reads[i]->getFile(); + cloned_file=true; + } } - if( !cloned_file ){ - ifile=new IFile(); - if( !ifile->FileExist(filename) ) error("could not find file named " + filename); - ifile->link(*this); - ifile->open(filename); - ifile->allowIgnoredFields(); + if( !cloned_file ) { + ifile=new IFile(); + if( !ifile->FileExist(filename) ) error("could not find file named " + filename); + ifile->link(*this); + ifile->open(filename); + ifile->allowIgnoredFields(); } parse("EVERY",nlinesPerStep); if(nlinesPerStep>1) log.printf(" only reading every %uth line of file %s\n",nlinesPerStep,filename.c_str() ); @@ -144,93 +144,93 @@ nlinesPerStep(1) std::vector<std::string> valread; parseVector("VALUES",valread); std::size_t dot=valread[0].find_first_of('.'); - if( valread[0].find(".")!=std::string::npos ){ - std::string label=valread[0].substr(0,dot); - std::string name=valread[0].substr(dot+1); - if( name=="*" ){ - if( valread.size()>1 ) error("all values must be from the same Action when using READ"); - std::vector<std::string> fieldnames; - ifile->scanFieldList( fieldnames ); - for(unsigned i=0;i<fieldnames.size();++i){ - if( fieldnames[i].substr(0,dot)==label ){ - readvals.push_back(new Value(this, fieldnames[i], false) ); addComponentWithDerivatives( fieldnames[i].substr(dot+1) ); - if( ifile->FieldExist("min_" + fieldnames[i]) ) componentIsPeriodic( fieldnames[i].substr(dot+1), "-pi","pi" ); - else componentIsNotPeriodic( fieldnames[i].substr(dot+1) ); - } - } - } else { - readvals.push_back(new Value(this, valread[0], false) ); addComponentWithDerivatives( name ); - if( ifile->FieldExist("min_" + valread[0]) ) componentIsPeriodic( valread[0].substr(dot+1), "-pi", "pi" ); - else componentIsNotPeriodic( valread[0].substr(dot+1) ); - for(unsigned i=1;i<valread.size();++i) { - if( valread[i].substr(0,dot)!=label ) error("all values must be from the same Action when using READ");; - readvals.push_back(new Value(this, valread[i], false) ); addComponentWithDerivatives( valread[i].substr(dot+1) ); - if( ifile->FieldExist("min_" + valread[i]) ) componentIsPeriodic( valread[i].substr(dot+1), "-pi", "pi" ); - else componentIsNotPeriodic( valread[i].substr(dot+1) ); - } + if( valread[0].find(".")!=std::string::npos ) { + std::string label=valread[0].substr(0,dot); + std::string name=valread[0].substr(dot+1); + if( name=="*" ) { + if( valread.size()>1 ) error("all values must be from the same Action when using READ"); + std::vector<std::string> fieldnames; + ifile->scanFieldList( fieldnames ); + for(unsigned i=0; i<fieldnames.size(); ++i) { + if( fieldnames[i].substr(0,dot)==label ) { + readvals.push_back(new Value(this, fieldnames[i], false) ); addComponentWithDerivatives( fieldnames[i].substr(dot+1) ); + if( ifile->FieldExist("min_" + fieldnames[i]) ) componentIsPeriodic( fieldnames[i].substr(dot+1), "-pi","pi" ); + else componentIsNotPeriodic( fieldnames[i].substr(dot+1) ); + } + } + } else { + readvals.push_back(new Value(this, valread[0], false) ); addComponentWithDerivatives( name ); + if( ifile->FieldExist("min_" + valread[0]) ) componentIsPeriodic( valread[0].substr(dot+1), "-pi", "pi" ); + else componentIsNotPeriodic( valread[0].substr(dot+1) ); + for(unsigned i=1; i<valread.size(); ++i) { + if( valread[i].substr(0,dot)!=label ) error("all values must be from the same Action when using READ");; + readvals.push_back(new Value(this, valread[i], false) ); addComponentWithDerivatives( valread[i].substr(dot+1) ); + if( ifile->FieldExist("min_" + valread[i]) ) componentIsPeriodic( valread[i].substr(dot+1), "-pi", "pi" ); + else componentIsNotPeriodic( valread[i].substr(dot+1) ); } + } } else { - if( valread.size()!=1 ) error("all values must be from the same Action when using READ"); - readvals.push_back(new Value(this, valread[0], false) ); addValueWithDerivatives(); - if( ifile->FieldExist("min_" + valread[0]) ) setPeriodic( "-pi", "pi" ); - else setNotPeriodic(); - log.printf(" reading value %s and storing as %s\n",valread[0].c_str() ,getLabel().c_str() ); + if( valread.size()!=1 ) error("all values must be from the same Action when using READ"); + readvals.push_back(new Value(this, valread[0], false) ); addValueWithDerivatives(); + if( ifile->FieldExist("min_" + valread[0]) ) setPeriodic( "-pi", "pi" ); + else setNotPeriodic(); + log.printf(" reading value %s and storing as %s\n",valread[0].c_str(),getLabel().c_str() ); } checkRead(); } -Read::~Read(){ - if( !cloned_file ){ ifile->close(); delete ifile; } - for(unsigned i=0;i<readvals.size();++i) delete readvals[i]; +Read::~Read() { + if( !cloned_file ) { ifile->close(); delete ifile; } + for(unsigned i=0; i<readvals.size(); ++i) delete readvals[i]; } std::string Read::getFilename() const { return filename; } -IFile* Read::getFile(){ +IFile* Read::getFile() { return ifile; } -unsigned Read::getNumberOfDerivatives(){ +unsigned Read::getNumberOfDerivatives() { return 0; } -void Read::turnOnDerivatives(){ +void Read::turnOnDerivatives() { if( !ignore_forces ) error("cannot calculate derivatives for colvars that are read in from a file. If you are postprocessing and " - "these forces do not matter add the flag IGNORE_FORCES to all READ actions"); + "these forces do not matter add the flag IGNORE_FORCES to all READ actions"); } -void Read::prepare(){ - if( !cloned_file ){ - double du_time; - if( !ifile->scanField("time",du_time) ){ - error("Reached end of file " + filename + " before end of trajectory"); - } else if( fabs( du_time-getTime() )>plumed.getAtoms().getTimeStep() && !ignore_time ){ - std::string str_dutime,str_ptime; Tools::convert(du_time,str_dutime); Tools::convert(getTime(),str_ptime); - error("mismatched times in colvar files : colvar time=" + str_dutime + " plumed time=" + str_ptime + ". Add IGNORE_TIME to ignore error."); - } - } +void Read::prepare() { + if( !cloned_file ) { + double du_time; + if( !ifile->scanField("time",du_time) ) { + error("Reached end of file " + filename + " before end of trajectory"); + } else if( fabs( du_time-getTime() )>plumed.getAtoms().getTimeStep() && !ignore_time ) { + std::string str_dutime,str_ptime; Tools::convert(du_time,str_dutime); Tools::convert(getTime(),str_ptime); + error("mismatched times in colvar files : colvar time=" + str_dutime + " plumed time=" + str_ptime + ". Add IGNORE_TIME to ignore error."); + } + } } -void Read::calculate(){ +void Read::calculate() { std::string smin, smax; - for(unsigned i=0;i<readvals.size();++i){ - ifile->scanField( readvals[i] ); - getPntrToComponent(i)->set( readvals[i]->get() ); - if( readvals[i]->isPeriodic() ){ - readvals[i]->getDomain( smin, smax ); - getPntrToComponent(i)->setDomain( smin, smax ); - } + for(unsigned i=0; i<readvals.size(); ++i) { + ifile->scanField( readvals[i] ); + getPntrToComponent(i)->set( readvals[i]->get() ); + if( readvals[i]->isPeriodic() ) { + readvals[i]->getDomain( smin, smax ); + getPntrToComponent(i)->setDomain( smin, smax ); + } } } -void Read::update(){ - if( !cloned_file ){ - for(unsigned i=0;i<nlinesPerStep;++i){ - ifile->scanField(); double du_time; - if( plumed.getAtoms().getNatoms()==0 && !ifile->scanField("time",du_time) ) plumed.stop(); - } +void Read::update() { + if( !cloned_file ) { + for(unsigned i=0; i<nlinesPerStep; ++i) { + ifile->scanField(); double du_time; + if( plumed.getAtoms().getNatoms()==0 && !ifile->scanField("time",du_time) ) plumed.stop(); + } } } diff --git a/src/generic/ResetCell.cpp b/src/generic/ResetCell.cpp index c595b4d9c..fd14c1fe1 100644 --- a/src/generic/ResetCell.cpp +++ b/src/generic/ResetCell.cpp @@ -35,7 +35,7 @@ using namespace std; namespace PLMD { -namespace generic{ +namespace generic { //+PLUMEDOC GENERIC RESET_CELL /* @@ -58,7 +58,7 @@ arbitrary. \attention The implementation of this action is available but should be considered in testing phase. Please report any -strange behavior. +strange behavior. \attention This directive modifies the stored position at the precise moment @@ -91,7 +91,7 @@ class ResetCell: { std::string type; Tensor rotation,newbox; - + public: explicit ResetCell(const ActionOptions&ao); static void registerKeywords( Keywords& keys ); @@ -101,7 +101,7 @@ public: PLUMED_REGISTER_ACTION(ResetCell,"RESET_CELL") -void ResetCell::registerKeywords( Keywords& keys ){ +void ResetCell::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionAtomistic::registerKeywords( keys ); keys.add("compulsory","STRIDE","1","the frequency with which molecules are reassembled. Unless you are completely certain about what you are doing leave this set equal to 1!"); @@ -109,66 +109,66 @@ void ResetCell::registerKeywords( Keywords& keys ){ } ResetCell::ResetCell(const ActionOptions&ao): -Action(ao), -ActionPilot(ao), -ActionAtomistic(ao) + Action(ao), + ActionPilot(ao), + ActionAtomistic(ao) { type.assign("TRIANGULAR"); parse("TYPE",type); log<<" type: "<<type<<"\n"; - if(type=="TRIANGULAR"){ + if(type=="TRIANGULAR") { } else error("undefined type "+type); checkRead(); } -void ResetCell::calculate(){ +void ResetCell::calculate() { - Pbc & pbc(modifyGlobalPbc()); + Pbc & pbc(modifyGlobalPbc()); - Tensor box=pbc.getBox(); + Tensor box=pbc.getBox(); // moduli of lattice vectors - double a=modulo(box.getRow(0)); - double b=modulo(box.getRow(1)); - double c=modulo(box.getRow(2)); + double a=modulo(box.getRow(0)); + double b=modulo(box.getRow(1)); + double c=modulo(box.getRow(2)); // cos-angle between lattice vectors - double ab=dotProduct(box.getRow(0),box.getRow(1))/(a*b); - double ac=dotProduct(box.getRow(0),box.getRow(2))/(a*c); - double bc=dotProduct(box.getRow(1),box.getRow(2))/(b*c); + double ab=dotProduct(box.getRow(0),box.getRow(1))/(a*b); + double ac=dotProduct(box.getRow(0),box.getRow(2))/(a*c); + double bc=dotProduct(box.getRow(1),box.getRow(2))/(b*c); // generate a new set of lattice vectors as a lower triangular matrix - newbox[0][0]=a; - newbox[1][0]=b*ab; - newbox[1][1]=std::sqrt(b*b-newbox[1][0]*newbox[1][0]); - newbox[2][0]=c*ac; - newbox[2][1]=c*(bc-ac*ab)/std::sqrt(1-ab*ab); - newbox[2][2]=std::sqrt(c*c-newbox[2][0]*newbox[2][0]-newbox[2][1]*newbox[2][1]); + newbox[0][0]=a; + newbox[1][0]=b*ab; + newbox[1][1]=std::sqrt(b*b-newbox[1][0]*newbox[1][0]); + newbox[2][0]=c*ac; + newbox[2][1]=c*(bc-ac*ab)/std::sqrt(1-ab*ab); + newbox[2][2]=std::sqrt(c*c-newbox[2][0]*newbox[2][0]-newbox[2][1]*newbox[2][1]); - if(determinant(newbox)*determinant(box)<0) newbox[2][2]=-newbox[2][2]; + if(determinant(newbox)*determinant(box)<0) newbox[2][2]=-newbox[2][2]; // rotation matrix from old to new coordinates - rotation=transpose(matmul(inverse(box),newbox)); + rotation=transpose(matmul(inverse(box),newbox)); // rotate all coordinates - for(unsigned i=0;i<getTotAtoms();i++){ - Vector & ato (modifyPosition(AtomNumber::index(i))); - ato=matmul(rotation,ato); - } + for(unsigned i=0; i<getTotAtoms(); i++) { + Vector & ato (modifyPosition(AtomNumber::index(i))); + ato=matmul(rotation,ato); + } // rotate box - pbc.setBox(newbox); + pbc.setBox(newbox); } -void ResetCell::apply(){ +void ResetCell::apply() { // rotate back forces - for(unsigned i=0;i<getTotAtoms(); i++) { - Vector & f(modifyGlobalForce(AtomNumber::index(i))); - f=matmul(transpose(rotation),f); - } + for(unsigned i=0; i<getTotAtoms(); i++) { + Vector & f(modifyGlobalForce(AtomNumber::index(i))); + f=matmul(transpose(rotation),f); + } - Tensor& virial(modifyGlobalVirial()); + Tensor& virial(modifyGlobalVirial()); // I have no mathematical derivation for this. // The reasoning is the following. // virial= h^T * dU/dh, where h is the box matrix and dU/dh its derivatives. @@ -181,11 +181,11 @@ void ResetCell::apply(){ // Thus, the only possibility is to set the corresponding elements // of the virial matrix equal to their symmetric ones. // GB - virial[0][1]=virial[1][0]; - virial[0][2]=virial[2][0]; - virial[1][2]=virial[2][1]; + virial[0][1]=virial[1][0]; + virial[0][2]=virial[2][0]; + virial[1][2]=virial[2][1]; // rotate back virial - virial=matmul(transpose(rotation),matmul(virial,rotation)); + virial=matmul(transpose(rotation),matmul(virial,rotation)); diff --git a/src/generic/Time.cpp b/src/generic/Time.cpp index 1cf216efc..3512cb53d 100644 --- a/src/generic/Time.cpp +++ b/src/generic/Time.cpp @@ -26,8 +26,8 @@ using namespace std; -namespace PLMD{ -namespace generic{ +namespace PLMD { +namespace generic { //+PLUMEDOC GENERIC TIME /* @@ -43,34 +43,34 @@ PRINT ARG=t1 */ //+ENDPLUMEDOC - + class Time : public ActionWithValue { public: static void registerKeywords( Keywords& keys ); explicit Time(const ActionOptions&); // active methods: virtual void calculate(); - virtual void apply(){} - unsigned getNumberOfDerivatives(){ return 0; } + virtual void apply() {} + unsigned getNumberOfDerivatives() { return 0; } }; PLUMED_REGISTER_ACTION(Time,"TIME") -void Time::registerKeywords( Keywords& keys ){ +void Time::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionWithValue::registerKeywords( keys ); } Time::Time(const ActionOptions&ao): -Action(ao),ActionWithValue(ao) + Action(ao),ActionWithValue(ao) { addValueWithDerivatives(); setNotPeriodic(); // resize derivative by hand to a nonzero value getPntrToValue()->resizeDerivatives(1); } -void Time::calculate(){ - setValue (getTime()); +void Time::calculate() { + setValue (getTime()); } } diff --git a/src/generic/UpdateIf.cpp b/src/generic/UpdateIf.cpp index 987cbc2c0..1db2b6cb1 100644 --- a/src/generic/UpdateIf.cpp +++ b/src/generic/UpdateIf.cpp @@ -26,8 +26,8 @@ using namespace std; -namespace PLMD{ -namespace generic{ +namespace PLMD { +namespace generic { //+PLUMEDOC PRINTANALYSIS UPDATE_IF /* @@ -76,8 +76,8 @@ UPDATE_IF ARG=coord END //+ENDPLUMEDOC class UpdateIf: -public ActionPilot, -public ActionWithArguments + public ActionPilot, + public ActionWithArguments { std::vector<double> lower; std::vector<double> upper; @@ -89,13 +89,13 @@ public: void beforeUpdate(); explicit UpdateIf(const ActionOptions&); static void registerKeywords(Keywords& keys); - void apply(){} + void apply() {} ~UpdateIf(); }; PLUMED_REGISTER_ACTION(UpdateIf,"UPDATE_IF") -void UpdateIf::registerKeywords(Keywords& keys){ +void UpdateIf::registerKeywords(Keywords& keys) { Action::registerKeywords(keys); ActionPilot::registerKeywords(keys); ActionWithArguments::registerKeywords(keys); @@ -107,11 +107,11 @@ void UpdateIf::registerKeywords(Keywords& keys){ } UpdateIf::UpdateIf(const ActionOptions&ao): -Action(ao), -ActionPilot(ao), -ActionWithArguments(ao), -on(false), -end(false) + Action(ao), + ActionPilot(ao), + ActionWithArguments(ao), + on(false), + end(false) { parseFlag("END",end); parseVector("LESS_THAN",upper); @@ -122,24 +122,24 @@ end(false) if(lower.size()==0) lower.assign(getNumberOfArguments(),-std::numeric_limits<double>::max()); if(upper.size()!=getNumberOfArguments()) error("LESS_THAN should have the same size as ARG"); if(lower.size()!=getNumberOfArguments()) error("MORE_THAN should have the same size as ARG"); - for(unsigned i=0;i<getNumberOfArguments();++i){ + for(unsigned i=0; i<getNumberOfArguments(); ++i) { log<<" boundaries for argument "<<i<<" "<<lower[i]<<" "<<upper[i]<<"\n"; } checkRead(); } -void UpdateIf::prepare(){ +void UpdateIf::prepare() { on=false; } -void UpdateIf::calculate(){ +void UpdateIf::calculate() { on=true; - for(unsigned i=0;i<getNumberOfArguments();++i){ + for(unsigned i=0; i<getNumberOfArguments(); ++i) { if(getArgument(i)>=upper[i] || getArgument(i)<=lower[i]) on=false; } } -void UpdateIf::beforeUpdate(){ +void UpdateIf::beforeUpdate() { if(end) plumed.updateFlagsPop(); else { if(on) plumed.updateFlagsPush(plumed.updateFlagsTop()); @@ -148,7 +148,7 @@ void UpdateIf::beforeUpdate(){ } -UpdateIf::~UpdateIf(){ +UpdateIf::~UpdateIf() { } } diff --git a/src/generic/WholeMolecules.cpp b/src/generic/WholeMolecules.cpp index 6d8551774..12e9c8281 100644 --- a/src/generic/WholeMolecules.cpp +++ b/src/generic/WholeMolecules.cpp @@ -36,7 +36,7 @@ using namespace std; namespace PLMD { -namespace generic{ +namespace generic { //+PLUMEDOC GENERIC WHOLEMOLECULES /* @@ -47,7 +47,7 @@ It is similar to the ALIGN_ATOMS keyword of plumed1, and is needed since some MD dynamics code (e.g. GROMACS) can break molecules during the calculation. Running some CVs without this command can cause there to be discontinuities changes -in the CV value and artifacts in the calculations. This command can be applied +in the CV value and artifacts in the calculations. This command can be applied more than once. To see what effect is has use a variable without pbc or use the \ref DUMPATOMS directive to output the atomic positions. @@ -90,12 +90,12 @@ DUMPATOMS FILE=dump.xyz ATOMS=1-20,30-40 \endverbatim (see also \ref DUMPATOMS) -This command instructs plumed to reconstruct the chain of backbone atoms in a +This command instructs plumed to reconstruct the chain of backbone atoms in a protein \verbatim MOLINFO STRUCTURE=helix.pdb -WHOLEMOLECULES RESIDUES=all MOLTYPE=protein +WHOLEMOLECULES RESIDUES=all MOLTYPE=protein \endverbatim (See also \ref MOLINFO) @@ -112,12 +112,12 @@ public: explicit WholeMolecules(const ActionOptions&ao); static void registerKeywords( Keywords& keys ); void calculate(); - void apply(){} + void apply() {} }; PLUMED_REGISTER_ACTION(WholeMolecules,"WHOLEMOLECULES") -void WholeMolecules::registerKeywords( Keywords& keys ){ +void WholeMolecules::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionPilot::registerKeywords( keys ); ActionAtomistic::registerKeywords( keys ); @@ -125,24 +125,24 @@ void WholeMolecules::registerKeywords( Keywords& keys ){ keys.add("numbered","ENTITY","the atoms that make up a molecule that you wish to align. To specify multiple molecules use a list of ENTITY keywords: ENTITY0, ENTITY1,..."); keys.reset_style("ENTITY","atoms"); keys.add("residues","RESIDUES","this command specifies that the backbone atoms in a set of residues all must be aligned. It must be used in tandem with the \\ref MOLINFO " - "action and the MOLTYPE keyword. If you wish to use all the residues from all the chains in your system you can do so by " - "specifying all. Alternatively, if you wish to use a subset of the residues you can specify the particular residues " - "you are interested in as a list of numbers"); + "action and the MOLTYPE keyword. If you wish to use all the residues from all the chains in your system you can do so by " + "specifying all. Alternatively, if you wish to use a subset of the residues you can specify the particular residues " + "you are interested in as a list of numbers"); keys.add("optional","MOLTYPE","the type of molecule that is under study. This is used to define the backbone atoms"); } WholeMolecules::WholeMolecules(const ActionOptions&ao): -Action(ao), -ActionPilot(ao), -ActionAtomistic(ao) + Action(ao), + ActionPilot(ao), + ActionAtomistic(ao) { vector<AtomNumber> merge; - for(int i=0;;i++){ + for(int i=0;; i++) { vector<AtomNumber> group; - parseAtomList("ENTITY",i,group); + parseAtomList("ENTITY",i,group); if( group.empty() ) break; log.printf(" atoms in entity %d : ",i); - for(unsigned j=0;j<group.size();++j) log.printf("%d ",group[j].serial() ); + for(unsigned j=0; j<group.size(); ++j) log.printf("%d ",group[j].serial() ); log.printf("\n"); groups.push_back(group); merge.insert(merge.end(),group.begin(),group.end()); @@ -150,23 +150,23 @@ ActionAtomistic(ao) // Read residues to align from MOLINFO vector<string> resstrings; parseVector("RESIDUES",resstrings); - if( resstrings.size()>0 ){ - if( resstrings.size()==1 ){ - if( resstrings[0]=="all" ) resstrings[0]="all-ter"; // Include terminal groups in alignment - } - string moltype; parse("MOLTYPE",moltype); - if(moltype.length()==0) error("Found RESIDUES keyword without specification of the moleclue - use MOLTYPE"); - std::vector<SetupMolInfo*> moldat=plumed.getActionSet().select<SetupMolInfo*>(); - if( moldat.size()==0 ) error("Unable to find MOLINFO in input"); - std::vector< std::vector<AtomNumber> > backatoms; - moldat[0]->getBackbone( resstrings, moltype, backatoms ); - for(unsigned i=0;i<backatoms.size();++i){ - log.printf(" atoms in entity %u : ", static_cast<unsigned>(groups.size()+1)); - for(unsigned j=0;j<backatoms[i].size();++j) log.printf("%d ",backatoms[i][j].serial() ); - log.printf("\n"); - groups.push_back( backatoms[i] ); - merge.insert(merge.end(),backatoms[i].begin(),backatoms[i].end()); - } + if( resstrings.size()>0 ) { + if( resstrings.size()==1 ) { + if( resstrings[0]=="all" ) resstrings[0]="all-ter"; // Include terminal groups in alignment + } + string moltype; parse("MOLTYPE",moltype); + if(moltype.length()==0) error("Found RESIDUES keyword without specification of the moleclue - use MOLTYPE"); + std::vector<SetupMolInfo*> moldat=plumed.getActionSet().select<SetupMolInfo*>(); + if( moldat.size()==0 ) error("Unable to find MOLINFO in input"); + std::vector< std::vector<AtomNumber> > backatoms; + moldat[0]->getBackbone( resstrings, moltype, backatoms ); + for(unsigned i=0; i<backatoms.size(); ++i) { + log.printf(" atoms in entity %u : ", static_cast<unsigned>(groups.size()+1)); + for(unsigned j=0; j<backatoms[i].size(); ++j) log.printf("%d ",backatoms[i][j].serial() ); + log.printf("\n"); + groups.push_back( backatoms[i] ); + merge.insert(merge.end(),backatoms[i].begin(),backatoms[i].end()); + } } if(groups.size()==0) error("no atom found for WHOLEMOLECULES!"); @@ -178,9 +178,9 @@ ActionAtomistic(ao) doNotForce(); } -void WholeMolecules::calculate(){ - for(unsigned i=0;i<groups.size();++i){ - for(unsigned j=0;j<groups[i].size()-1;++j){ +void WholeMolecules::calculate() { + for(unsigned i=0; i<groups.size(); ++i) { + for(unsigned j=0; j<groups[i].size()-1; ++j) { const Vector & first (getPosition(groups[i][j])); Vector & second (modifyPosition(groups[i][j+1])); second=first+pbcDistance(first,second); diff --git a/src/generic/WrapAround.cpp b/src/generic/WrapAround.cpp index 50872db30..946a060fd 100644 --- a/src/generic/WrapAround.cpp +++ b/src/generic/WrapAround.cpp @@ -37,7 +37,7 @@ using namespace std; namespace PLMD { -namespace generic{ +namespace generic { //+PLUMEDOC GENERIC WRAPAROUND /* @@ -89,7 +89,7 @@ RESTRAINT ARG=a AT=0.0 KAPPA=5 # then do the things that are required for dumping the trajectory -# notice that they are all done every 100 steps, so as not to +# notice that they are all done every 100 steps, so as not to # unnecessarily overload the calculation rna: GROUP ATOMS=1-100 @@ -163,12 +163,12 @@ public: explicit WrapAround(const ActionOptions&ao); static void registerKeywords( Keywords& keys ); void calculate(); - void apply(){} + void apply() {} }; PLUMED_REGISTER_ACTION(WrapAround,"WRAPAROUND") -void WrapAround::registerKeywords( Keywords& keys ){ +void WrapAround::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionAtomistic::registerKeywords( keys ); ActionPilot::registerKeywords( keys ); @@ -179,25 +179,25 @@ void WrapAround::registerKeywords( Keywords& keys ){ } WrapAround::WrapAround(const ActionOptions&ao): -Action(ao), -ActionPilot(ao), -ActionAtomistic(ao), -groupby(1) + Action(ao), + ActionPilot(ao), + ActionAtomistic(ao), + groupby(1) { parseAtomList("ATOMS",atoms); parseAtomList("AROUND",reference); parse("GROUPBY",groupby); log.printf(" atoms in reference :"); - for(unsigned j=0;j<reference.size();++j) log.printf(" %d",reference[j].serial() ); + for(unsigned j=0; j<reference.size(); ++j) log.printf(" %d",reference[j].serial() ); log.printf("\n"); log.printf(" atoms to be wrapped :"); - for(unsigned j=0;j<atoms.size();++j) log.printf(" %d",atoms[j].serial() ); + for(unsigned j=0; j<atoms.size(); ++j) log.printf(" %d",atoms[j].serial() ); log.printf("\n"); if(groupby>1) log<<" atoms will be grouped by "<<groupby<<"\n"; if(atoms.size()%groupby!=0) error("number of atoms should be a multiple of groupby option"); - + checkRead(); if(groupby<=1) Tools::removeDuplicates(atoms); @@ -211,16 +211,16 @@ groupby(1) doNotForce(); } -void WrapAround::calculate(){ - for(unsigned i=0;i<atoms.size();i+=groupby){ +void WrapAround::calculate() { + for(unsigned i=0; i<atoms.size(); i+=groupby) { Vector & first (modifyPosition(atoms[i])); double mindist2=std::numeric_limits<double>::max(); int closest=-1; - for(unsigned j=0;j<reference.size();++j){ + for(unsigned j=0; j<reference.size(); ++j) { Vector & second (modifyPosition(reference[j])); Vector distance=pbcDistance(first,second); double distance2=modulo2(distance); - if(distance2<mindist2){ + if(distance2<mindist2) { mindist2=distance2; closest=j; } @@ -230,7 +230,7 @@ void WrapAround::calculate(){ // place first atom of the group first=second+pbcDistance(second,first); // then place other atoms close to the first of the group - for(unsigned j=1;j<groupby;j++){ + for(unsigned j=1; j<groupby; j++) { Vector & second (modifyPosition(atoms[i+j])); second=first+pbcDistance(first,second); } diff --git a/src/gridtools/ActionWithGrid.cpp b/src/gridtools/ActionWithGrid.cpp index 2da36a0a2..2957ffd91 100644 --- a/src/gridtools/ActionWithGrid.cpp +++ b/src/gridtools/ActionWithGrid.cpp @@ -26,57 +26,57 @@ namespace PLMD { namespace gridtools { -void ActionWithGrid::registerKeywords( Keywords& keys ){ +void ActionWithGrid::registerKeywords( Keywords& keys ) { vesselbase::ActionWithAveraging::registerKeywords( keys ); keys.add("compulsory","BANDWIDTH","the bandwidths for kernel density esimtation"); keys.add("compulsory","KERNEL","gaussian","the kernel function you are using. More details on the kernels available " - "in plumed plumed can be found in \\ref kernelfunctions."); + "in plumed plumed can be found in \\ref kernelfunctions."); keys.add("optional","CONCENTRATION","the concentration parameter for Von Mises-Fisher distributions"); } ActionWithGrid::ActionWithGrid( const ActionOptions& ao): -Action(ao), -ActionWithAveraging(ao), -mygrid(NULL) + Action(ao), + ActionWithAveraging(ao), + mygrid(NULL) { } -void ActionWithGrid::createGrid( const std::string& type, const std::string& inputstr ){ +void ActionWithGrid::createGrid( const std::string& type, const std::string& inputstr ) { // Start creating the input for the grid - std::string vstring = inputstr; - if( keywords.exists("KERNEL") ){ - std::string vconc; parse("CONCENTRATION",vconc); - if( vconc.length()>0 ){ - vstring += " TYPE=fibonacci CONCENTRATION=" + vconc; - } else { - std::string kstring; parse("KERNEL",kstring); - if( kstring=="DISCRETE" ) vstring += " KERNEL=" + kstring; - else vstring += " KERNEL=" + kstring + " " + getKeyword("BANDWIDTH"); - } + std::string vstring = inputstr; + if( keywords.exists("KERNEL") ) { + std::string vconc; parse("CONCENTRATION",vconc); + if( vconc.length()>0 ) { + vstring += " TYPE=fibonacci CONCENTRATION=" + vconc; + } else { + std::string kstring; parse("KERNEL",kstring); + if( kstring=="DISCRETE" ) vstring += " KERNEL=" + kstring; + else vstring += " KERNEL=" + kstring + " " + getKeyword("BANDWIDTH"); + } } vesselbase::VesselOptions da("mygrid","",-1,vstring,this); Keywords keys; gridtools::AverageOnGrid::registerKeywords( keys ); vesselbase::VesselOptions dar( da, keys ); - if( type=="histogram" ){ - mygrid = new HistogramOnGrid(dar); - } else if( type=="average" ){ - mygrid = new AverageOnGrid(dar); - } else if( type=="grid" ){ - mygrid = new GridVessel(dar); + if( type=="histogram" ) { + mygrid = new HistogramOnGrid(dar); + } else if( type=="average" ) { + mygrid = new AverageOnGrid(dar); + } else if( type=="grid" ) { + mygrid = new GridVessel(dar); } else { - plumed_merror("no way to create grid of type " + type ); - } + plumed_merror("no way to create grid of type " + type ); + } } -void ActionWithGrid::turnOnDerivatives(){ - needsDerivatives(); ActionWithValue::turnOnDerivatives(); +void ActionWithGrid::turnOnDerivatives() { + needsDerivatives(); ActionWithValue::turnOnDerivatives(); if( getStride()==1 ) setStride(0); else if( getStride()!=0 ) error("conflicting instructions for grid - stride was set but must be evaluated on every step for derivatives - remove STRIDE keyword"); - if( clearstride>1 ) error("conflicting instructions for grid - CLEAR was set but grid must be reset on every step for derivatives - remove CLEAR keyword" ); - if( weights.size()>0 ) error("conflicting instructions for grid - LOGWEIGHTS was set but weights are not considered when derivatives of grid are evaluated - remove LOGWEIGHTS keyword"); + if( clearstride>1 ) error("conflicting instructions for grid - CLEAR was set but grid must be reset on every step for derivatives - remove CLEAR keyword" ); + if( weights.size()>0 ) error("conflicting instructions for grid - LOGWEIGHTS was set but weights are not considered when derivatives of grid are evaluated - remove LOGWEIGHTS keyword"); } -void ActionWithGrid::calculate(){ +void ActionWithGrid::calculate() { // Do nothing if derivatives are not required if( doNotCalculateDerivatives() ) return; // Clear on every step diff --git a/src/gridtools/ActionWithGrid.h b/src/gridtools/ActionWithGrid.h index f87c5e6e6..c01a50ef1 100644 --- a/src/gridtools/ActionWithGrid.h +++ b/src/gridtools/ActionWithGrid.h @@ -43,7 +43,7 @@ protected: void createGrid( const std::string& type, const std::string& inputstr ); public: static void registerKeywords( Keywords& keys ); - explicit ActionWithGrid( const ActionOptions& ); + explicit ActionWithGrid( const ActionOptions& ); virtual void turnOnDerivatives(); void calculate(); void performTask( const unsigned& task_index, const unsigned& current, MultiValue& myvals ) const ; diff --git a/src/gridtools/ActionWithInputGrid.cpp b/src/gridtools/ActionWithInputGrid.cpp index e409d9662..12d358115 100644 --- a/src/gridtools/ActionWithInputGrid.cpp +++ b/src/gridtools/ActionWithInputGrid.cpp @@ -26,52 +26,52 @@ namespace PLMD { namespace gridtools { -void ActionWithInputGrid::registerKeywords( Keywords& keys ){ +void ActionWithInputGrid::registerKeywords( Keywords& keys ) { ActionWithGrid::registerKeywords( keys ); keys.add("compulsory","GRID","the action that creates the input grid you would like to use"); keys.add("optional","COMPONENT","if your input is a vector field use this to specifiy the component of the input vector field for which you wish to use"); } ActionWithInputGrid::ActionWithInputGrid(const ActionOptions&ao): -Action(ao), -ActionWithGrid(ao), -ingrid(NULL) + Action(ao), + ActionWithGrid(ao), + ingrid(NULL) { std::string mlab; parse("GRID",mlab); vesselbase::ActionWithVessel* mves= plumed.getActionSet().selectWithLabel<vesselbase::ActionWithVessel*>(mlab); if(!mves) error("action labelled " + mlab + " does not exist or does not have vessels"); addDependency(mves); - for(unsigned i=0;i<mves->getNumberOfVessels();++i){ - ingrid=dynamic_cast<GridVessel*>( mves->getPntrToVessel(i) ); - if( ingrid ) break; + for(unsigned i=0; i<mves->getNumberOfVessels(); ++i) { + ingrid=dynamic_cast<GridVessel*>( mves->getPntrToVessel(i) ); + if( ingrid ) break; } if( !ingrid ) error("input action does not calculate a grid"); - if( ingrid->getNumberOfComponents()==1 ){ - mycomp=0; + if( ingrid->getNumberOfComponents()==1 ) { + mycomp=0; } else { - int tcomp=-1; parse("COMPONENT",tcomp); - if( tcomp<0 ) error("component of vector field was not specified - use COMPONENT keyword"); - mycomp=tcomp; + int tcomp=-1; parse("COMPONENT",tcomp); + if( tcomp<0 ) error("component of vector field was not specified - use COMPONENT keyword"); + mycomp=tcomp; } log.printf(" using %uth component of grid calculated by action %s \n",mycomp,mves->getLabel().c_str() ); } -void ActionWithInputGrid::clearAverage(){ +void ActionWithInputGrid::clearAverage() { if( mygrid->getType()=="flat" ) mygrid->setBounds( ingrid->getMin(), ingrid->getMax(), mygrid->getNbin(), mygrid->getGridSpacing() ); ActionWithAveraging::clearAverage(); } -void ActionWithInputGrid::prepareForAveraging(){ - if( checkAllActive() ){ - for(unsigned i=0;i<ingrid->getNumberOfPoints();++i){ - if( ingrid->inactive(i) ) error("if FIND_CONTOUR is used with BUFFER option then other actions cannot be performed with grid"); - } +void ActionWithInputGrid::prepareForAveraging() { + if( checkAllActive() ) { + for(unsigned i=0; i<ingrid->getNumberOfPoints(); ++i) { + if( ingrid->inactive(i) ) error("if FIND_CONTOUR is used with BUFFER option then other actions cannot be performed with grid"); + } } } -void ActionWithInputGrid::performOperations( const bool& from_update ){ +void ActionWithInputGrid::performOperations( const bool& from_update ) { prepareForAveraging(); runAllTasks(); } diff --git a/src/gridtools/ActionWithInputGrid.h b/src/gridtools/ActionWithInputGrid.h index 0799f4de6..cc1ba009e 100644 --- a/src/gridtools/ActionWithInputGrid.h +++ b/src/gridtools/ActionWithInputGrid.h @@ -29,7 +29,7 @@ namespace PLMD { namespace gridtools { class ActionWithInputGrid : public ActionWithGrid { -friend class DumpGrid; + friend class DumpGrid; private: unsigned mycomp; protected: @@ -44,12 +44,12 @@ public: virtual void prepareForAveraging(); virtual bool checkAllActive() const { return true; } virtual void performOperations( const bool& from_update ); - virtual void apply(){}; + virtual void apply() {}; }; inline double ActionWithInputGrid::getFunctionValue( const unsigned& ipoint ) const { - unsigned dim=ingrid->getDimension(); if( ingrid->noderiv ) dim=0; + unsigned dim=ingrid->getDimension(); if( ingrid->noderiv ) dim=0; return ingrid->getGridElement( ipoint, mycomp*(1+dim) ); } @@ -61,7 +61,7 @@ double ActionWithInputGrid::getFunctionValue( const std::vector<unsigned>& ip ) inline double ActionWithInputGrid::getFunctionValueAndDerivatives( const std::vector<double>& x, std::vector<double>& der ) const { return ingrid->getValueAndDerivatives( x, mycomp, der ); -} +} } } diff --git a/src/gridtools/ActionWithIntegral.cpp b/src/gridtools/ActionWithIntegral.cpp index addfb46db..7deb7fbd3 100644 --- a/src/gridtools/ActionWithIntegral.cpp +++ b/src/gridtools/ActionWithIntegral.cpp @@ -24,37 +24,37 @@ namespace PLMD { namespace gridtools { -void ActionWithIntegral::registerKeywords( Keywords& keys ){ +void ActionWithIntegral::registerKeywords( Keywords& keys ) { ActionWithInputGrid::registerKeywords( keys ); - keys.remove("KERNEL"); keys.remove("BANDWIDTH"); + keys.remove("KERNEL"); keys.remove("BANDWIDTH"); keys.remove("CLEAR"); keys.add("compulsory","CLEAR","1","the frequency with which to clear all the accumulated data."); } ActionWithIntegral::ActionWithIntegral(const ActionOptions&ao): -Action(ao), -ActionWithInputGrid(ao) + Action(ao), + ActionWithInputGrid(ao) { - plumed_assert( ingrid->getNumberOfComponents()==1 ); + plumed_assert( ingrid->getNumberOfComponents()==1 ); // Retrieve the volume of the grid (for integration) volume = ingrid->getCellVolume(); - // Create something that is going to calculate the sum of all the values + // Create something that is going to calculate the sum of all the values // at the various grid points - this is going to be the integral std::string fake_input; addVessel( "SUM", fake_input, -1 ); readVesselKeywords(); // Now create task list - number of tasks is equal to the number of grid points // as we have to evaluate the function at each grid points - for(unsigned i=0;i<ingrid->getNumberOfPoints();++i) addTaskToList(i); + for(unsigned i=0; i<ingrid->getNumberOfPoints(); ++i) addTaskToList(i); // And activate all tasks - deactivateAllTasks(); - for(unsigned i=0;i<ingrid->getNumberOfPoints();++i) taskFlags[i]=1; + deactivateAllTasks(); + for(unsigned i=0; i<ingrid->getNumberOfPoints(); ++i) taskFlags[i]=1; lockContributors(); } -void ActionWithIntegral::turnOnDerivatives(){ +void ActionWithIntegral::turnOnDerivatives() { ActionWithGrid::turnOnDerivatives(); forcesToApply.resize( ingrid->getNumberOfPoints() ); } -void ActionWithIntegral::apply(){ +void ActionWithIntegral::apply() { if( getForcesFromVessels( forcesToApply ) ) ingrid->setForce( forcesToApply ); } diff --git a/src/gridtools/ActionWithIntegral.h b/src/gridtools/ActionWithIntegral.h index 635ce663b..b4fcbf2b9 100644 --- a/src/gridtools/ActionWithIntegral.h +++ b/src/gridtools/ActionWithIntegral.h @@ -40,7 +40,7 @@ public: unsigned getNumberOfDerivatives(); void turnOnDerivatives(); /// Unless I am mistaken an integral should never be a periodic function - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } void apply(); }; @@ -50,7 +50,7 @@ double ActionWithIntegral::getVolume() const { } inline -unsigned ActionWithIntegral::getNumberOfDerivatives(){ +unsigned ActionWithIntegral::getNumberOfDerivatives() { return ingrid->getNumberOfPoints(); } diff --git a/src/gridtools/AverageOnGrid.cpp b/src/gridtools/AverageOnGrid.cpp index 75d04579b..0f9c5cc73 100644 --- a/src/gridtools/AverageOnGrid.cpp +++ b/src/gridtools/AverageOnGrid.cpp @@ -24,16 +24,16 @@ namespace PLMD { namespace gridtools { -void AverageOnGrid::registerKeywords( Keywords& keys ){ +void AverageOnGrid::registerKeywords( Keywords& keys ) { HistogramOnGrid::registerKeywords( keys ); } AverageOnGrid::AverageOnGrid( const vesselbase::VesselOptions& da ): -HistogramOnGrid(da) + HistogramOnGrid(da) { arg_names.push_back( "density" ); - if( !discrete ){ - for(unsigned i=0;i<dimension;++i) arg_names.push_back( "ddensity_" + arg_names[i] ); + if( !discrete ) { + for(unsigned i=0; i<dimension; ++i) arg_names.push_back( "ddensity_" + arg_names[i] ); nper += (dimension+1); } else { nper += 1; @@ -42,27 +42,27 @@ HistogramOnGrid(da) void AverageOnGrid::accumulate( const unsigned& ipoint, const double& weight, const double& dens, const std::vector<double>& der, std::vector<double>& buffer ) const { buffer[bufstart+nper*ipoint] += weight*dens; buffer[ bufstart+nper*(ipoint+1) - (dimension+1) ] += dens; - if( der.size()>0 ){ - for(unsigned j=0;j<dimension;++j) buffer[ bufstart+nper*ipoint + 1 + j ] += weight*der[j]; - for(unsigned j=0;j<dimension;++j) buffer[ bufstart+nper*(ipoint+1) - dimension + j ] += der[j]; + if( der.size()>0 ) { + for(unsigned j=0; j<dimension; ++j) buffer[ bufstart+nper*ipoint + 1 + j ] += weight*der[j]; + for(unsigned j=0; j<dimension; ++j) buffer[ bufstart+nper*(ipoint+1) - dimension + j ] += der[j]; } } double AverageOnGrid::getGridElement( const unsigned& ipoint, const unsigned& jelement ) const { - if( noAverage() ) return getDataElement( nper*ipoint + jelement); + if( noAverage() ) return getDataElement( nper*ipoint + jelement); - if( jelement>=(nper-(dimension+1)) ) return getDataElement( nper*ipoint + jelement ); + if( jelement>=(nper-(dimension+1)) ) return getDataElement( nper*ipoint + jelement ); if( noderiv ) return getDataElement( nper*ipoint+jelement ) / getDataElement( nper*(1+ipoint) - 1); - double rdenom = 1.0; + double rdenom = 1.0; if( fabs(getDataElement( nper*(ipoint+1) -(dimension+1) ))>epsilon ) rdenom = 1. / getDataElement( nper*(ipoint+1) - (dimension+1) ); - + unsigned jderiv = jelement%(1+dimension); - if( jderiv==0 ) return rdenom*getDataElement( nper*ipoint+jelement ); + if( jderiv==0 ) return rdenom*getDataElement( nper*ipoint+jelement ); unsigned jfloor = std::floor( jelement / (1+dimension) ); - return rdenom*getDataElement( nper*ipoint+jelement ) - rdenom*rdenom*getDataElement(nper*ipoint+jfloor)*getDataElement(nper*(ipoint+1) - (dimension+1) + jderiv); + return rdenom*getDataElement( nper*ipoint+jelement ) - rdenom*rdenom*getDataElement(nper*ipoint+jfloor)*getDataElement(nper*(ipoint+1) - (dimension+1) + jderiv); } } diff --git a/src/gridtools/AverageOnGrid.h b/src/gridtools/AverageOnGrid.h index 8b224bf05..ad38b50e7 100644 --- a/src/gridtools/AverageOnGrid.h +++ b/src/gridtools/AverageOnGrid.h @@ -35,7 +35,7 @@ public: void accumulateForce( const unsigned& ipoint, const double& weight, const std::vector<double>& der, std::vector<double>& intforce ) const { plumed_error(); } double getGridElement( const unsigned& ipoint, const unsigned& jelement ) const ; unsigned getNumberOfComponents() const ; - void getFinalForces( const std::vector<double>& buffer, std::vector<double>& finalForces ){ plumed_error(); } + void getFinalForces( const std::vector<double>& buffer, std::vector<double>& finalForces ) { plumed_error(); } }; inline diff --git a/src/gridtools/ContourFindingBase.cpp b/src/gridtools/ContourFindingBase.cpp index cb6d374f5..3a20dd672 100644 --- a/src/gridtools/ContourFindingBase.cpp +++ b/src/gridtools/ContourFindingBase.cpp @@ -24,19 +24,19 @@ namespace PLMD { namespace gridtools { -void ContourFindingBase::registerKeywords( Keywords& keys ){ +void ContourFindingBase::registerKeywords( Keywords& keys ) { ActionWithInputGrid::registerKeywords( keys ); keys.add("compulsory","CONTOUR","the value we would like to draw the contour at in the space"); keys.remove("KERNEL"); keys.remove("BANDWIDTH"); } ContourFindingBase::ContourFindingBase(const ActionOptions&ao): -Action(ao), -ActionWithInputGrid(ao), -mymin(this) + Action(ao), + ActionWithInputGrid(ao), + mymin(this) { if( ingrid->noDerivatives() ) error("cannot find contours if input grid has no derivatives"); - parse("CONTOUR",contour); + parse("CONTOUR",contour); log.printf(" calculating dividing surface along which function equals %f \n", contour); } diff --git a/src/gridtools/ContourFindingBase.h b/src/gridtools/ContourFindingBase.h index ec6c1eee9..5a1752d5e 100644 --- a/src/gridtools/ContourFindingBase.h +++ b/src/gridtools/ContourFindingBase.h @@ -43,9 +43,9 @@ public: /// Get the contour value double getDifferenceFromContour( const std::vector<double>& x, std::vector<double>& der ) const ; /// Overwrite not needed stuff - unsigned getNumberOfDerivatives(){ return 0; } + unsigned getNumberOfDerivatives() { return 0; } /// This is not periodic - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } }; inline diff --git a/src/gridtools/ConvertToFES.cpp b/src/gridtools/ConvertToFES.cpp index 1edf196f0..4e3bbdf17 100644 --- a/src/gridtools/ConvertToFES.cpp +++ b/src/gridtools/ConvertToFES.cpp @@ -42,13 +42,13 @@ The free energy calculated on a grid is output by this action and can be printed This is a typical example showing how CONVERT_TO_FES might be used when postprocessing a trajectory. The input below calculates the free energy as a function of the distance between atom 1 and atom 2. This is done by accumulating a histogram as a function of this distance using kernel density estimation -and the HISTOGRAM action. All the data within this trajectory is used in the construction of this -HISTOGRAM. Finally, once all the data has been read in, the histogram is converted to a free energy +and the HISTOGRAM action. All the data within this trajectory is used in the construction of this +HISTOGRAM. Finally, once all the data has been read in, the histogram is converted to a free energy using the formula above and the free energy is output to a file called fes.dat \verbatim x: DISTANCE ATOMS=1,2 -hA1: HISTOGRAM ARG=x GRID_MIN=0.0 GRID_MAX=3.0 GRID_BIN=100 BANDWIDTH=0.1 +hA1: HISTOGRAM ARG=x GRID_MIN=0.0 GRID_MAX=3.0 GRID_BIN=100 BANDWIDTH=0.1 ff: CONVERT_TO_FES GRID=hA1 TEMP=300 DUMPGRID GRID=ff FILE=fes.dat \endverbatim @@ -67,35 +67,35 @@ public: static void registerKeywords( Keywords& keys ); explicit ConvertToFES(const ActionOptions&ao); unsigned getNumberOfQuantities() const ; - void prepare(){ activated=true; } - void prepareForAveraging(){ ActionWithInputGrid::prepareForAveraging(); activated=false; } + void prepare() { activated=true; } + void prepareForAveraging() { ActionWithInputGrid::prepareForAveraging(); activated=false; } void compute( const unsigned& current, MultiValue& myvals ) const ; - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } bool onStep() const { return activated; } void runFinalJobs(); }; PLUMED_REGISTER_ACTION(ConvertToFES,"CONVERT_TO_FES") -void ConvertToFES::registerKeywords( Keywords& keys ){ +void ConvertToFES::registerKeywords( Keywords& keys ) { ActionWithInputGrid::registerKeywords( keys ); keys.add("optional","TEMP","the temperature at which you are operating"); - keys.remove("STRIDE"); keys.remove("KERNEL"); keys.remove("BANDWIDTH"); + keys.remove("STRIDE"); keys.remove("KERNEL"); keys.remove("BANDWIDTH"); keys.remove("LOGWEIGHTS"); keys.remove("CLEAR"); keys.remove("UNORMALIZED"); } ConvertToFES::ConvertToFES(const ActionOptions&ao): -Action(ao), -ActionWithInputGrid(ao), -activated(false) + Action(ao), + ActionWithInputGrid(ao), + activated(false) { plumed_assert( ingrid->getNumberOfComponents()==1 ); // Create a grid - createGrid( "grid", "COMPONENTS=" + getLabel() + " " + ingrid->getInputString() ); - if( ingrid->noDerivatives() ) mygrid->setNoDerivatives(); + createGrid( "grid", "COMPONENTS=" + getLabel() + " " + ingrid->getInputString() ); + if( ingrid->noDerivatives() ) mygrid->setNoDerivatives(); std::vector<double> fspacing; - mygrid->setBounds( ingrid->getMin(), ingrid->getMax(), ingrid->getNbin(), fspacing); + mygrid->setBounds( ingrid->getMin(), ingrid->getMax(), ingrid->getNbin(), fspacing); setAveragingAction( mygrid, true ); simtemp=0.; parse("TEMP",simtemp); @@ -104,10 +104,10 @@ activated(false) if( simtemp==0 ) error("TEMP not set - use keyword TEMP"); // Now create task list - for(unsigned i=0;i<mygrid->getNumberOfPoints();++i) addTaskToList(i); + for(unsigned i=0; i<mygrid->getNumberOfPoints(); ++i) addTaskToList(i); // And activate all tasks - deactivateAllTasks(); - for(unsigned i=0;i<mygrid->getNumberOfPoints();++i) taskFlags[i]=1; + deactivateAllTasks(); + for(unsigned i=0; i<mygrid->getNumberOfPoints(); ++i) taskFlags[i]=1; lockContributors(); } @@ -118,12 +118,12 @@ unsigned ConvertToFES::getNumberOfQuantities() const { void ConvertToFES::compute( const unsigned& current, MultiValue& myvals ) const { double val=getFunctionValue( current ); myvals.setValue(1, -simtemp*std::log(val) ); - if( !mygrid->noDerivatives() && val>0 ){ - for(unsigned i=0;i<mygrid->getDimension();++i) myvals.setValue( 2+i, -(simtemp/val)*ingrid->getGridElement(current,i+1) ); + if( !mygrid->noDerivatives() && val>0 ) { + for(unsigned i=0; i<mygrid->getDimension(); ++i) myvals.setValue( 2+i, -(simtemp/val)*ingrid->getGridElement(current,i+1) ); } } -void ConvertToFES::runFinalJobs(){ +void ConvertToFES::runFinalJobs() { activated=true; update(); } diff --git a/src/gridtools/DumpCube.cpp b/src/gridtools/DumpCube.cpp index 22676175b..0fbc47f56 100644 --- a/src/gridtools/DumpCube.cpp +++ b/src/gridtools/DumpCube.cpp @@ -28,22 +28,22 @@ Output a three dimensional grid using the Gaussian cube file format. Suppose you have calculated the value of a function on a three dimensional grid. -This function might be a \ref HISTOGRAM or it might be a free energy energy surface +This function might be a \ref HISTOGRAM or it might be a free energy energy surface that was calculated from this histogram by using \ref CONVERT_TO_FES. Alternatively, your function might be a phase-field that was calculated using \ref MULTICOLVARDENS. Whatever the function is, however, you obviously cannot show it using a typical contour -plotting program such as gnuplot as you have three input variables. +plotting program such as gnuplot as you have three input variables. Tools like VMD have nice features for plotting these types of three dimensional functions -but typically you are required to use a Gaussian cube file format to input the data. This +but typically you are required to use a Gaussian cube file format to input the data. This action thus allows you to output a function evaluated on a grid to a Gaussian cube file format. \par Examples The input below can be used to postprocess a trajectory. A histogram as a function of the distance between atoms 1 and 2, the distance between atom 1 and 3 and the angle between the vector connecting atoms 1 and -2 and 1 and 3 is computed using kernel density estimation. Once all the data contained in the trajectory has been read in and -all the kernels have been added the resulting histogram is output to a file called histoA1.cube. This file has the +2 and 1 and 3 is computed using kernel density estimation. Once all the data contained in the trajectory has been read in and +all the kernels have been added the resulting histogram is output to a file called histoA1.cube. This file has the Gaussian cube file format. The histogram can thus be visualized using tools such as VMD. \verbatim @@ -52,7 +52,7 @@ x2: DISTANCE ATOMS=1,3 x3: ANGLE ATOMS=1,2,3 hA1: HISTOGRAM ARG=x1,x2,x3 GRID_MIN=0.0,0.0,0.0 GRID_MAX=3.0,3.0,3.0 GRID_BIN=10,10,10 BANDWIDTH=1.0,1.0,1.0 -DUMPCUBE GRID=hA1 FILE=histoA1.cube +DUMPCUBE GRID=hA1 FILE=histoA1.cube \endverbatim */ @@ -66,32 +66,32 @@ private: unsigned mycomp; public: static void registerKeywords( Keywords& keys ); - explicit DumpCube(const ActionOptions&ao); + explicit DumpCube(const ActionOptions&ao); void printGrid( OFile& ofile ) const ; }; PLUMED_REGISTER_ACTION(DumpCube,"DUMPCUBE") -void DumpCube::registerKeywords( Keywords& keys ){ +void DumpCube::registerKeywords( Keywords& keys ) { GridPrintingBase::registerKeywords( keys ); keys.add("optional","COMPONENT","if your input is a vector field use this to specifiy the component of the input vector field for which you wish to output"); } DumpCube::DumpCube(const ActionOptions&ao): -Action(ao), -GridPrintingBase(ao) + Action(ao), + GridPrintingBase(ao) { fmt = fmt + " "; if( ingrid->getType()!="flat" ) error("cannot dump grid of type " + ingrid->getType() + " using DUMPCUBE"); if( ingrid->getDimension()!=3 ) error("cannot print cube file if grid does not contain three dimensional data"); - if( ingrid->getNumberOfComponents()==1 ){ - mycomp=0; + if( ingrid->getNumberOfComponents()==1 ) { + mycomp=0; } else { - int tcomp=-1; parse("COMPONENT",tcomp); - if( tcomp<0 ) error("component of vector field was not specified - use COMPONENT keyword"); - mycomp=tcomp*(1+ingrid->getDimension()); if( ingrid->noDerivatives() ) mycomp=tcomp; - log.printf(" using %dth component of grid \n",tcomp ); + int tcomp=-1; parse("COMPONENT",tcomp); + if( tcomp<0 ) error("component of vector field was not specified - use COMPONENT keyword"); + mycomp=tcomp*(1+ingrid->getDimension()); if( ingrid->noDerivatives() ) mycomp=tcomp; + log.printf(" using %dth component of grid \n",tcomp ); } checkRead(); @@ -105,19 +105,19 @@ void DumpCube::printGrid( OFile& ofile ) const { // Number of atoms followed by position of origin (origin set so that center of grid is in center of cell) std::string ostr = "%d " + fmt + fmt + fmt + "\n"; ofile.printf(ostr.c_str(),1,-0.5*lunit*ingrid->getGridExtent(0),-0.5*lunit*ingrid->getGridExtent(1),-0.5*lunit*ingrid->getGridExtent(2)); - ofile.printf(ostr.c_str(),ingrid->getNbin()[0],lunit*ingrid->getGridSpacing()[0],0.0,0.0); // Number of bins in each direction followed by + ofile.printf(ostr.c_str(),ingrid->getNbin()[0],lunit*ingrid->getGridSpacing()[0],0.0,0.0); // Number of bins in each direction followed by ofile.printf(ostr.c_str(),ingrid->getNbin()[1],0.0,lunit*ingrid->getGridSpacing()[1],0.0); // shape of voxel ofile.printf(ostr.c_str(),ingrid->getNbin()[2],0.0,0.0,lunit*ingrid->getGridSpacing()[2]); ofile.printf(ostr.c_str(),1,0.0,0.0,0.0); // Fake atom otherwise VMD doesn't work std::vector<unsigned> pp(3); std::vector<unsigned> nbin( ingrid->getNbin() ); - for(pp[0]=0;pp[0]<nbin[0];++pp[0]){ - for(pp[1]=0;pp[1]<nbin[1];++pp[1]){ - for(pp[2]=0;pp[2]<nbin[2];++pp[2]){ - ofile.printf(fmt.c_str(), ingrid->getGridElement( ingrid->getIndex(pp), mycomp ) ); - if(pp[2]%6==5) ofile.printf("\n"); - } - ofile.printf("\n"); - } + for(pp[0]=0; pp[0]<nbin[0]; ++pp[0]) { + for(pp[1]=0; pp[1]<nbin[1]; ++pp[1]) { + for(pp[2]=0; pp[2]<nbin[2]; ++pp[2]) { + ofile.printf(fmt.c_str(), ingrid->getGridElement( ingrid->getIndex(pp), mycomp ) ); + if(pp[2]%6==5) ofile.printf("\n"); + } + ofile.printf("\n"); + } } } diff --git a/src/gridtools/DumpGrid.cpp b/src/gridtools/DumpGrid.cpp index acbcdc805..608742a8b 100644 --- a/src/gridtools/DumpGrid.cpp +++ b/src/gridtools/DumpGrid.cpp @@ -32,12 +32,12 @@ Output the function on the grid to a file with the PLUMED grid format. PLUMED provides a number of actions that calculate the values of functions on grids. For instance, whenver you calculate a free energy as a function of a collective variable using -\ref HISTOGRAM and \ref CONVERT_TO_FES you will generally want to output the value of the free energy at a number of points on a +\ref HISTOGRAM and \ref CONVERT_TO_FES you will generally want to output the value of the free energy at a number of points on a discrete grid that covers the CV space uniformly. Alternatively you may want to calculate -what value some symmetry function takes at different points inside your simulation cell using \ref MULTICOLVARDENS. +what value some symmetry function takes at different points inside your simulation cell using \ref MULTICOLVARDENS. -This action allows you to output these functions calculated on a grid using a format that can be read in using gnuplot -and other such plotting programs. The file output using this action will have a header that contains some essential +This action allows you to output these functions calculated on a grid using a format that can be read in using gnuplot +and other such plotting programs. The file output using this action will have a header that contains some essential information about the function plotted and that looks something like this: \verbatim @@ -51,17 +51,17 @@ information about the function plotted and that looks something like this: #! SET max_y 3.0 #! SET nbins_y 100 #! SET periodic_y false -\endverbatim +\endverbatim -The header shown here tells us that we have grid showing the values that a function with two arguments x and y -takes at various points in our cell. The lines beheath the first line then tell us a little bit about these two -input arguments. +The header shown here tells us that we have grid showing the values that a function with two arguments x and y +takes at various points in our cell. The lines beheath the first line then tell us a little bit about these two +input arguments. -The remaining lines of the file give us information on the positions of our grid points and the value the function and -its partial derivatives with respect to x and y. If the header is as above a list of values of the function that have +The remaining lines of the file give us information on the positions of our grid points and the value the function and +its partial derivatives with respect to x and y. If the header is as above a list of values of the function that have x=0 and 100 values of y between 0.0 and 3.0 will be provided. This block of data will be followed with a blank line. There will then be a second block of values which will all have been evaluated the same value of x and all possible values -for y. This block is then followed by a blank line again and this pattern continues until all points of the grid have been covered. +for y. This block is then followed by a blank line again and this pattern continues until all points of the grid have been covered. \par Examples @@ -71,11 +71,11 @@ and outputs a continuos histogram as a function of them at the end of the simula TORSION ATOMS=1,2,3,4 LABEL=r1 TORSION ATOMS=2,3,4,5 LABEL=r2 HISTOGRAM ... - ARG=r1,r2 - GRID_MIN=-3.14,-3.14 - GRID_MAX=3.14,3.14 + ARG=r1,r2 + GRID_MIN=-3.14,-3.14 + GRID_MAX=3.14,3.14 GRID_BIN=200,200 - BANDWIDTH=0.05,0.05 + BANDWIDTH=0.05,0.05 LABEL=hh ... HISTOGRAM @@ -88,11 +88,11 @@ and outputs a discrete histogram as a function of them at the end of the simulat TORSION ATOMS=1,2,3,4 LABEL=r1 TORSION ATOMS=2,3,4,5 LABEL=r2 HISTOGRAM ... - ARG=r1,r2 + ARG=r1,r2 USE_ALL_DATA KERNEL=DISCRETE - GRID_MIN=-3.14,-3.14 - GRID_MAX=3.14,3.14 + GRID_MIN=-3.14,-3.14 + GRID_MAX=3.14,3.14 GRID_BIN=200,200 LABEL=hh ... HISTOGRAM @@ -106,11 +106,11 @@ and outputs the histogram accumulated thus far every 100000 steps. TORSION ATOMS=1,2,3,4 LABEL=r1 TORSION ATOMS=2,3,4,5 LABEL=r2 HISTOGRAM ... - ARG=r1,r2 - GRID_MIN=-3.14,-3.14 - GRID_MAX=3.14,3.14 + ARG=r1,r2 + GRID_MIN=-3.14,-3.14 + GRID_MAX=3.14,3.14 GRID_BIN=200,200 - BANDWIDTH=0.05,0.05 + BANDWIDTH=0.05,0.05 LABEL=hh ... HISTOGRAM @@ -119,18 +119,18 @@ DUMPGRID GRID=hh FILE=histo STRIDE=100000 The following input monitors two torsional angles during a simulation and outputs a separate histogram for each 100000 steps worth of trajectory. -Notice how the CLEAR keyword is used here and how it is not used in the +Notice how the CLEAR keyword is used here and how it is not used in the previous example. \verbatim TORSION ATOMS=1,2,3,4 LABEL=r1 TORSION ATOMS=2,3,4,5 LABEL=r2 HISTOGRAM ... - ARG=r1,r2 CLEAR=100000 - GRID_MIN=-3.14,-3.14 - GRID_MAX=3.14,3.14 + ARG=r1,r2 CLEAR=100000 + GRID_MIN=-3.14,-3.14 + GRID_MAX=3.14,3.14 GRID_BIN=200,200 - BANDWIDTH=0.05,0.05 + BANDWIDTH=0.05,0.05 GRID_WFILE=histo LABEL=hh ... HISTOGRAM @@ -144,19 +144,19 @@ DUMPGRID GRID=hh FILE=histo STRIDE=100000 class DumpGrid : public GridPrintingBase { public: static void registerKeywords( Keywords& keys ); - explicit DumpGrid(const ActionOptions&ao); + explicit DumpGrid(const ActionOptions&ao); void printGrid( OFile& ofile ) const ; }; PLUMED_REGISTER_ACTION(DumpGrid,"DUMPGRID") -void DumpGrid::registerKeywords( Keywords& keys ){ +void DumpGrid::registerKeywords( Keywords& keys ) { GridPrintingBase::registerKeywords( keys ); } DumpGrid::DumpGrid(const ActionOptions&ao): -Action(ao), -GridPrintingBase(ao) + Action(ao), + GridPrintingBase(ao) { if( ingrid->getType()!="flat" ) error("cannot dump grid of type " + ingrid->getType() + " using DUMPGRID"); fmt = " " + fmt; checkRead(); @@ -164,33 +164,33 @@ GridPrintingBase(ao) void DumpGrid::printGrid( OFile& ofile ) const { ofile.addConstantField("normalisation"); - for(unsigned i=0;i<ingrid->getDimension();++i){ - ofile.addConstantField("min_" + ingrid->getComponentName(i) ); - ofile.addConstantField("max_" + ingrid->getComponentName(i) ); - ofile.addConstantField("nbins_" + ingrid->getComponentName(i) ); - ofile.addConstantField("periodic_" + ingrid->getComponentName(i) ); + for(unsigned i=0; i<ingrid->getDimension(); ++i) { + ofile.addConstantField("min_" + ingrid->getComponentName(i) ); + ofile.addConstantField("max_" + ingrid->getComponentName(i) ); + ofile.addConstantField("nbins_" + ingrid->getComponentName(i) ); + ofile.addConstantField("periodic_" + ingrid->getComponentName(i) ); } std::vector<double> xx( ingrid->getDimension() ); std::vector<unsigned> ind( ingrid->getDimension() ); - for(unsigned i=0;i<ingrid->getNumberOfPoints();++i){ - ingrid->getIndices( i, ind ); - if(i>0 && ingrid->getDimension()==2 && ind[ingrid->getDimension()-2]==0) ofile.printf("\n"); - ofile.fmtField(fmt); ofile.printField("normalisation", ingrid->getNorm() ); - for(unsigned j=0;j<ingrid->getDimension();++j){ - ofile.printField("min_" + ingrid->getComponentName(j), ingrid->getMin()[j] ); - ofile.printField("max_" + ingrid->getComponentName(j), ingrid->getMax()[j] ); - ofile.printField("nbins_" + ingrid->getComponentName(j), static_cast<int>(ingrid->getNbin()[j]) ); - if( ingrid->isPeriodic(j) ) ofile.printField("periodic_" + ingrid->getComponentName(j), "true" ); - else ofile.printField("periodic_" + ingrid->getComponentName(j), "false" ); - } - // Retrieve and print the grid coordinates - ingrid->getGridPointCoordinates(i, xx ); - for(unsigned j=0;j<ingrid->getDimension();++j){ ofile.fmtField(fmt); ofile.printField(ingrid->getComponentName(j),xx[j]); } - for(unsigned j=0;j<ingrid->getNumberOfQuantities();++j){ - ofile.fmtField(fmt); ofile.printField(ingrid->arg_names[ingrid->dimension+j], ingrid->getGridElement( i, j ) ); - } - ofile.printField(); + for(unsigned i=0; i<ingrid->getNumberOfPoints(); ++i) { + ingrid->getIndices( i, ind ); + if(i>0 && ingrid->getDimension()==2 && ind[ingrid->getDimension()-2]==0) ofile.printf("\n"); + ofile.fmtField(fmt); ofile.printField("normalisation", ingrid->getNorm() ); + for(unsigned j=0; j<ingrid->getDimension(); ++j) { + ofile.printField("min_" + ingrid->getComponentName(j), ingrid->getMin()[j] ); + ofile.printField("max_" + ingrid->getComponentName(j), ingrid->getMax()[j] ); + ofile.printField("nbins_" + ingrid->getComponentName(j), static_cast<int>(ingrid->getNbin()[j]) ); + if( ingrid->isPeriodic(j) ) ofile.printField("periodic_" + ingrid->getComponentName(j), "true" ); + else ofile.printField("periodic_" + ingrid->getComponentName(j), "false" ); + } + // Retrieve and print the grid coordinates + ingrid->getGridPointCoordinates(i, xx ); + for(unsigned j=0; j<ingrid->getDimension(); ++j) { ofile.fmtField(fmt); ofile.printField(ingrid->getComponentName(j),xx[j]); } + for(unsigned j=0; j<ingrid->getNumberOfQuantities(); ++j) { + ofile.fmtField(fmt); ofile.printField(ingrid->arg_names[ingrid->dimension+j], ingrid->getGridElement( i, j ) ); + } + ofile.printField(); } } diff --git a/src/gridtools/FindContour.cpp b/src/gridtools/FindContour.cpp index 1fb94949a..a58e4f650 100644 --- a/src/gridtools/FindContour.cpp +++ b/src/gridtools/FindContour.cpp @@ -29,14 +29,14 @@ /* Find an isocontour in a smooth function. -As discussed in the part of the manual on \ref Analysis PLUMED contains a number of tools that allow you to calculate -a function on a grid. The function on this grid might be a \ref HISTOGRAM as a function of a few collective variables +As discussed in the part of the manual on \ref Analysis PLUMED contains a number of tools that allow you to calculate +a function on a grid. The function on this grid might be a \ref HISTOGRAM as a function of a few collective variables or it might be a phase field that has been calcualted using \ref MULTICOLVARDENS. If this function has one or two input arguments it is relatively straightforward to plot the function. If by contrast the data has a three or more dimensions -it can be difficult to visualize. +it can be difficult to visualize. -This action provides one tool for visualizing these functions. It can be used to search for a set of points on a contour -where the function takes a particular values. In other words, for the function \f$f(x,y)\f$ this action would find a set +This action provides one tool for visualizing these functions. It can be used to search for a set of points on a contour +where the function takes a particular values. In other words, for the function \f$f(x,y)\f$ this action would find a set of points \f$\{x_c,y_c\}\f$ that have: \f[ @@ -55,14 +55,14 @@ Furthermore, the topology of the contour will be determined by the algorithm and \par Examples The input below allows you to calculate something akin to a Willard-Chandler dividing surface \cite wcsurface. -The simulation cell in this case contains a solid phase and a liquid phase. The Willard-Chandler surface is the +The simulation cell in this case contains a solid phase and a liquid phase. The Willard-Chandler surface is the surface that separates the parts of the box containing the solid from the parts containing the liquid. To compute the position of this surface the \ref FCCUBIC symmetry function is calculated for each of the atoms in the system from on the geometry of the atoms in the first coordination sphere of each of the atoms. These quantities are then transformed using a switching function. -This procedure generates a single number for each atom in the system and this quantity has a value of one for atoms that are in +This procedure generates a single number for each atom in the system and this quantity has a value of one for atoms that are in parts of the box that resemble the solid structure and zero for atoms that are in parts of the box that resemble the liquid. The position of a virtual atom is then computed using \ref CENTER_OF_MULTICOLVAR and a phase field model is constructed using -\ref MULTICOLVARDENS. These procedure ensures that we have a continuous function that gives a measure of the average degree of +\ref MULTICOLVARDENS. These procedure ensures that we have a continuous function that gives a measure of the average degree of solidness at each point in the simulation cell. The Willard-Chandler dividing surface is calculated by finding a a set of points at which the value of this phase field is equal to 0.5. This set of points is output to file called mycontour.dat. A new contour is found on every single step for each frame that is read in. @@ -70,20 +70,20 @@ is found on every single step for each frame that is read in. \verbatim UNITS NATURAL FCCUBIC ... - SPECIES=1-96000 SWITCH={CUBIC D_0=1.2 D_MAX=1.5} + SPECIES=1-96000 SWITCH={CUBIC D_0=1.2 D_MAX=1.5} ALPHA=27 PHI=0.0 THETA=-1.5708 PSI=-2.35619 LABEL=fcc ... FCCUBIC tfcc: MTRANSFORM_MORE DATA=fcc SWITCH={SMAP R_0=0.5 A=8 B=8} center: CENTER_OF_MULTICOLVAR DATA=tfcc -MULTICOLVARDENS ... - DATA=tfcc ORIGIN=center DIR=xyz LABEL=dens +MULTICOLVARDENS ... + DATA=tfcc ORIGIN=center DIR=xyz LABEL=dens NBINS=80,80,80 BANDWIDTH=1.0,1.0,1.0 STRIDE=25 LABEL=dens STRIDE=1 CLEAR=1 ... MULTICOLVARDENS -FIND_CONTOUR GRID=dens CONTOUR=0.5 FILE=mycontour.dat +FIND_CONTOUR GRID=dens CONTOUR=0.5 FILE=mycontour.dat \endverbatim */ @@ -96,7 +96,7 @@ class FindContour : public ContourFindingBase { private: bool firsttime; unsigned gbuffer; -/// Stuff for output +/// Stuff for output OFile of; double lenunit; std::string fmt_xyz; @@ -107,7 +107,7 @@ public: explicit FindContour(const ActionOptions&ao); bool checkAllActive() const { return gbuffer==0; } void prepareForAveraging(); - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } unsigned getNumberOfQuantities() const { return 1 + ingrid->getDimension(); } void compute( const unsigned& current, MultiValue& myvals ) const ; void finishAveraging(); @@ -115,7 +115,7 @@ public: PLUMED_REGISTER_ACTION(FindContour,"FIND_CONTOUR") -void FindContour::registerKeywords( Keywords& keys ){ +void FindContour::registerKeywords( Keywords& keys ) { ContourFindingBase::registerKeywords( keys ); // We want a better way of doing this bit keys.add("compulsory","BUFFER","0","number of buffer grid points around location where grid was found on last step. If this is zero the full grid is calculated on each step"); @@ -125,9 +125,9 @@ void FindContour::registerKeywords( Keywords& keys ){ } FindContour::FindContour(const ActionOptions&ao): -Action(ao), -ContourFindingBase(ao), -firsttime(true) + Action(ao), + ContourFindingBase(ao), + firsttime(true) { parse("BUFFER",gbuffer); @@ -137,20 +137,20 @@ firsttime(true) if( file.length()==0 ) error("name out output file was not specified"); std::string type=Tools::extension(file); log<<" file name "<<file<<"\n"; - if(type!="xyz") error("can only print xyz file type with contour finding"); + if(type!="xyz") error("can only print xyz file type with contour finding"); fmt_xyz="%f"; std::string precision; parse("PRECISION",precision); - if(precision.length()>0){ - int p; Tools::convert(precision,p); - log<<" with precision "<<p<<"\n"; - std::string a,b; - Tools::convert(p+5,a); - Tools::convert(p,b); - fmt_xyz="%"+a+"."+b+"f"; + if(precision.length()>0) { + int p; Tools::convert(precision,p); + log<<" with precision "<<p<<"\n"; + std::string a,b; + Tools::convert(p+5,a); + Tools::convert(p,b); + fmt_xyz="%"+a+"."+b+"f"; } std::string unitname; parse("UNITS",unitname); - if(unitname!="PLUMED"){ + if(unitname!="PLUMED") { Units myunit; myunit.setLength(unitname); lenunit=plumed.getAtoms().getUnits().getLength()/myunit.getLength(); } @@ -159,10 +159,10 @@ firsttime(true) checkRead(); mydata=buildDataStashes( NULL ); } -void FindContour::prepareForAveraging(){ +void FindContour::prepareForAveraging() { // Create a task list if first time - if( firsttime ){ - for(unsigned i=0;i<ingrid->getDimension()*ingrid->getNumberOfPoints();++i) addTaskToList( i ); + if( firsttime ) { + for(unsigned i=0; i<ingrid->getDimension()*ingrid->getNumberOfPoints(); ++i) addTaskToList( i ); } firsttime=false; deactivateAllTasks(); @@ -171,34 +171,34 @@ void FindContour::prepareForAveraging(){ std::vector<unsigned> ind( ingrid->getDimension() ); std::vector<unsigned> ones( ingrid->getDimension(), 1 ); unsigned num_neighbours; std::vector<unsigned> neighbours; - for(unsigned i=0;i<ingrid->getNumberOfPoints();++i){ - // Ensure inactive grid points are ignored - if( ingrid->inactive(i) ) continue; - - // Get the index of the current grid point - ingrid->getIndices( i, ind ); - ingrid->getNeighbors( ind, ones, num_neighbours, neighbours ); - bool cycle=false; - for(unsigned j=0;j<num_neighbours;++j){ - if( ingrid->inactive( neighbours[j]) ){ cycle=true; break; } - } - if( cycle ) continue; - - // Get the value of a point on the grid - double val1=getFunctionValue( i ) - contour; - bool edge=false; - for(unsigned j=0;j<ingrid->getDimension();++j){ - // Make sure we don't search at the edge of the grid - if( !ingrid->isPeriodic(j) && (ind[j]+1)==nbin[j] ) continue; - else if( (ind[j]+1)==nbin[j] ){ edge=true; ind[j]=0; } - else ind[j]+=1; - double val2=getFunctionValue( ind ) - contour; - if( val1*val2<0 ) taskFlags[ ingrid->getDimension()*i + j ] = 1; - if( ingrid->isPeriodic(j) && edge ){ edge=false; ind[j]=nbin[j]-1; } - else ind[j]-=1; - } + for(unsigned i=0; i<ingrid->getNumberOfPoints(); ++i) { + // Ensure inactive grid points are ignored + if( ingrid->inactive(i) ) continue; + + // Get the index of the current grid point + ingrid->getIndices( i, ind ); + ingrid->getNeighbors( ind, ones, num_neighbours, neighbours ); + bool cycle=false; + for(unsigned j=0; j<num_neighbours; ++j) { + if( ingrid->inactive( neighbours[j]) ) { cycle=true; break; } + } + if( cycle ) continue; + + // Get the value of a point on the grid + double val1=getFunctionValue( i ) - contour; + bool edge=false; + for(unsigned j=0; j<ingrid->getDimension(); ++j) { + // Make sure we don't search at the edge of the grid + if( !ingrid->isPeriodic(j) && (ind[j]+1)==nbin[j] ) continue; + else if( (ind[j]+1)==nbin[j] ) { edge=true; ind[j]=0; } + else ind[j]+=1; + double val2=getFunctionValue( ind ) - contour; + if( val1*val2<0 ) taskFlags[ ingrid->getDimension()*i + j ] = 1; + if( ingrid->isPeriodic(j) && edge ) { edge=false; ind[j]=nbin[j]-1; } + else ind[j]-=1; + } } - lockContributors(); + lockContributors(); } void FindContour::compute( const unsigned& current, MultiValue& myvals ) const { @@ -209,40 +209,40 @@ void FindContour::compute( const unsigned& current, MultiValue& myvals ) const { // Retrieve the direction we are searching for the contour unsigned gdir = current%(ingrid->getDimension() ); - std::vector<double> direction( ingrid->getDimension() , 0 ); + std::vector<double> direction( ingrid->getDimension(), 0 ); direction[gdir] = 0.999999999*ingrid->getGridSpacing()[gdir]; // Now find the contour findContour( direction, point ); // And transfer to the store data vessel - for(unsigned i=0;i<ingrid->getDimension();++i) myvals.setValue( 1+i, point[i] ); + for(unsigned i=0; i<ingrid->getDimension(); ++i) myvals.setValue( 1+i, point[i] ); } -void FindContour::finishAveraging(){ +void FindContour::finishAveraging() { // And update the list of active grid points - if( gbuffer>0 ){ - std::vector<unsigned> neighbours; unsigned num_neighbours; - std::vector<unsigned> ugrid_indices( ingrid->getDimension() ); - std::vector<bool> active( ingrid->getNumberOfPoints(), false ); - std::vector<unsigned> gbuffer_vec( ingrid->getDimension(), gbuffer ); - for(unsigned i=0;i<getCurrentNumberOfActiveTasks();++i){ - // Get the point we are operating on - unsigned ipoint = std::floor( getActiveTask(i) / ingrid->getDimension() ); - // Get the indices of this point - ingrid->getIndices( ipoint, ugrid_indices ); - // Now activate buffer region - ingrid->getNeighbors( ugrid_indices , gbuffer_vec, num_neighbours, neighbours ); - for(unsigned n=0;n<num_neighbours;++n) active[ neighbours[n] ]=true; - } - ingrid->activateThesePoints( active ); + if( gbuffer>0 ) { + std::vector<unsigned> neighbours; unsigned num_neighbours; + std::vector<unsigned> ugrid_indices( ingrid->getDimension() ); + std::vector<bool> active( ingrid->getNumberOfPoints(), false ); + std::vector<unsigned> gbuffer_vec( ingrid->getDimension(), gbuffer ); + for(unsigned i=0; i<getCurrentNumberOfActiveTasks(); ++i) { + // Get the point we are operating on + unsigned ipoint = std::floor( getActiveTask(i) / ingrid->getDimension() ); + // Get the indices of this point + ingrid->getIndices( ipoint, ugrid_indices ); + // Now activate buffer region + ingrid->getNeighbors( ugrid_indices, gbuffer_vec, num_neighbours, neighbours ); + for(unsigned n=0; n<num_neighbours; ++n) active[ neighbours[n] ]=true; + } + ingrid->activateThesePoints( active ); } std::vector<double> point( 1 + ingrid->getDimension() ); of.printf("%u\n",mydata->getNumberOfStoredValues()); of.printf("Points found on isocontour\n"); - for(unsigned i=0;i<mydata->getNumberOfStoredValues();++i){ - mydata->retrieveSequentialValue( i, false, point ); of.printf("X"); - for(unsigned j=0;j<ingrid->getDimension();++j) of.printf( (" " + fmt_xyz).c_str(), lenunit*point[1+j] ); - of.printf("\n"); + for(unsigned i=0; i<mydata->getNumberOfStoredValues(); ++i) { + mydata->retrieveSequentialValue( i, false, point ); of.printf("X"); + for(unsigned j=0; j<ingrid->getDimension(); ++j) of.printf( (" " + fmt_xyz).c_str(), lenunit*point[1+j] ); + of.printf("\n"); } } diff --git a/src/gridtools/FindContourSurface.cpp b/src/gridtools/FindContourSurface.cpp index 6a83c0abd..ce24d757f 100644 --- a/src/gridtools/FindContourSurface.cpp +++ b/src/gridtools/FindContourSurface.cpp @@ -26,14 +26,14 @@ /* Find an isocontour by searching along either the x, y or z direction. -As discussed in the part of the manual on \ref Analysis PLUMED contains a number of tools that allow you to calculate -a function on a grid. The function on this grid might be a \ref HISTOGRAM as a function of a few collective variables +As discussed in the part of the manual on \ref Analysis PLUMED contains a number of tools that allow you to calculate +a function on a grid. The function on this grid might be a \ref HISTOGRAM as a function of a few collective variables or it might be a phase field that has been calcualted using \ref MULTICOLVARDENS. If this function has one or two input -arguments it is relatively straightforward to plot the function. If by contrast the data has a three dimensions it can be +arguments it is relatively straightforward to plot the function. If by contrast the data has a three dimensions it can be difficult to visualize. -This action provides one tool for visualizing these functions. It can be used to search for a set of points on a contour -wher the function takes a particular value. In other words, for the function \f$f(x,y,z)\f$ this action would find a set +This action provides one tool for visualizing these functions. It can be used to search for a set of points on a contour +wher the function takes a particular value. In other words, for the function \f$f(x,y,z)\f$ this action would find a set of points \f$\{x_c,y_c,z_c\}\f$ that have: \f[ @@ -41,34 +41,34 @@ f(x_c,y_c,z_c) - c = 0 \f] where \f$c\f$ is some constant value that is specified by the user. The points on this contour are find by searching along lines -that run parallel to the \f$x\f$, \f$y\f$ or \f$z\f$ axis of the simulation cell. The result is, therefore, a two dimensional -function evaluated on a grid that gives us the height of the interface as a function of two coordinates. +that run parallel to the \f$x\f$, \f$y\f$ or \f$z\f$ axis of the simulation cell. The result is, therefore, a two dimensional +function evaluated on a grid that gives us the height of the interface as a function of two coordinates. -It is important to note that this action can only be used to detect countours in three dimensional functions. In addition, this action will fail to -find the full set of contour points if the contour does not have the same topology as an infinite plane. If you are uncertain that the isocontours in your +It is important to note that this action can only be used to detect countours in three dimensional functions. In addition, this action will fail to +find the full set of contour points if the contour does not have the same topology as an infinite plane. If you are uncertain that the isocontours in your function have the appropriate topology you should use \ref FIND_CONTOUR in place of \ref FIND_CONTOUR_SURFACE. \par Examples -The input shown below was used to analyse the results from a simulation of an interface between solid and molten Lennard Jones. The interface between -the solid and the liquid was set up in the plane perpendicular to the \f$z\f$ direction of the simulation cell. The input below calculates something -akin to a Willard-Chandler dividing surface \cite wcsurface between the solid phase and the liquid phase. There are two of these interfaces within the -simulation box because of the periodic boundary conditions but we were able to determine that one of these two surfaces lies in a particular part of the -simulation box. The input below detects the height profile of one of these two interfaces. It does so by computing a phase field average of the +The input shown below was used to analyse the results from a simulation of an interface between solid and molten Lennard Jones. The interface between +the solid and the liquid was set up in the plane perpendicular to the \f$z\f$ direction of the simulation cell. The input below calculates something +akin to a Willard-Chandler dividing surface \cite wcsurface between the solid phase and the liquid phase. There are two of these interfaces within the +simulation box because of the periodic boundary conditions but we were able to determine that one of these two surfaces lies in a particular part of the +simulation box. The input below detects the height profile of one of these two interfaces. It does so by computing a phase field average of the \ref FCCUBIC symmetry function using the \ref MULTICOLVARDENS action. Notice that we use the fact that we know roughly where the interface is when specifying -how this phase field is to be calculated and specify the region over the \f$z\f$-axis in which we are going to search for the phase field in the line defining +how this phase field is to be calculated and specify the region over the \f$z\f$-axis in which we are going to search for the phase field in the line defining the \ref MULTICOLVARDENS. Once we have calculated the phase field we search for contour points on the lines that run parallel to the \f$z\f$-direction of the cell -box using the FIND_CONTOUR_SURFACE command. The final result is a \f$14 \times 14\f$ grid of values for the height of the interface as a function of the \f$(x,y)\f$ +box using the FIND_CONTOUR_SURFACE command. The final result is a \f$14 \times 14\f$ grid of values for the height of the interface as a function of the \f$(x,y)\f$ position. This grid is then output to a file called contour2.dat. Notice that the commands below calculate the instantaneous position of the surface separating the solid and liquid and that as such the accumulated average is cleared -on every step. +on every step. \verbatim UNITS NATURAL FCCUBIC ... - SPECIES=1-96000 SWITCH={CUBIC D_0=1.2 D_MAX=1.5} + SPECIES=1-96000 SWITCH={CUBIC D_0=1.2 D_MAX=1.5} ALPHA=27 PHI=0.0 THETA=-1.5708 PSI=-2.35619 LABEL=fcc ... FCCUBIC @@ -105,17 +105,17 @@ public: PLUMED_REGISTER_ACTION(FindContourSurface,"FIND_CONTOUR_SURFACE") -void FindContourSurface::registerKeywords( Keywords& keys ){ +void FindContourSurface::registerKeywords( Keywords& keys ) { ContourFindingBase::registerKeywords( keys ); keys.add("compulsory","SEARCHDIR","In which directions do you wish to search for the contour."); keys.add("compulsory","BUFFER","0","number of buffer grid points around location where grid was found on last step. If this is zero the full grid is calculated on each step"); } FindContourSurface::FindContourSurface(const ActionOptions&ao): -Action(ao), -ContourFindingBase(ao), -firsttime(true), -ones(ingrid->getDimension(),1) + Action(ao), + ContourFindingBase(ao), + firsttime(true), + ones(ingrid->getDimension(),1) { if( ingrid->getDimension()<2 ) error("cannot find dividing surface if input grid is one dimensional"); @@ -125,85 +125,85 @@ ones(ingrid->getDimension(),1) checkRead(); unsigned n=0; gdirs.resize( ingrid->getDimension()-1 ); - for(unsigned i=0;i<ingrid->getDimension();++i){ - if( ingrid->getComponentName(i)==dir ){ - dir_n=i; - } else { - if( n==gdirs.size() ) error("could not find " + dir + " direction in input grid"); - gdirs[n]=i; n++; - } + for(unsigned i=0; i<ingrid->getDimension(); ++i) { + if( ingrid->getComponentName(i)==dir ) { + dir_n=i; + } else { + if( n==gdirs.size() ) error("could not find " + dir + " direction in input grid"); + gdirs[n]=i; n++; + } } if( n!=(ingrid->getDimension()-1) ) error("output of grid is not understood"); // Create the input from the old string std::string vstring = "COMPONENTS=" + getLabel() + " COORDINATES=" + ingrid->getComponentName( gdirs[0] ); - for(unsigned i=1;i<gdirs.size();++i) vstring += "," + ingrid->getComponentName( gdirs[i] ); + for(unsigned i=1; i<gdirs.size(); ++i) vstring += "," + ingrid->getComponentName( gdirs[i] ); vstring += " PBC="; if( ingrid->isPeriodic(gdirs[0]) ) vstring+="T"; else vstring+="F"; - for(unsigned i=1;i<gdirs.size();++i){ - if( ingrid->isPeriodic(gdirs[i]) ) vstring+=",T"; else vstring+=",F"; + for(unsigned i=1; i<gdirs.size(); ++i) { + if( ingrid->isPeriodic(gdirs[i]) ) vstring+=",T"; else vstring+=",F"; } - createGrid( "grid", vstring ); mygrid->setNoDerivatives(); + createGrid( "grid", vstring ); mygrid->setNoDerivatives(); setAveragingAction( mygrid, true ); } -void FindContourSurface::clearAverage(){ +void FindContourSurface::clearAverage() { // Set the boundaries of the output grid std::vector<double> fspacing; std::vector<unsigned> snbins( ingrid->getDimension()-1 ); std::vector<std::string> smin( ingrid->getDimension()-1 ), smax( ingrid->getDimension()-1 ); - for(unsigned i=0;i<gdirs.size();++i){ - smin[i]=ingrid->getMin()[gdirs[i]]; smax[i]=ingrid->getMax()[gdirs[i]]; - snbins[i]=ingrid->getNbin()[gdirs[i]]; - } + for(unsigned i=0; i<gdirs.size(); ++i) { + smin[i]=ingrid->getMin()[gdirs[i]]; smax[i]=ingrid->getMax()[gdirs[i]]; + snbins[i]=ingrid->getNbin()[gdirs[i]]; + } mygrid->setBounds( smin, smax, snbins, fspacing); resizeFunctions(); ActionWithAveraging::clearAverage(); } -void FindContourSurface::prepareForAveraging(){ +void FindContourSurface::prepareForAveraging() { // Create a task list if first time - if( firsttime ){ - std::vector<unsigned> find( ingrid->getDimension() ); - std::vector<unsigned> ind( mygrid->getDimension() ); - for(unsigned i=0;i<mygrid->getNumberOfPoints();++i){ - find.assign( find.size(), 0 ); mygrid->getIndices( i, ind ); - for(unsigned j=0;j<gdirs.size();++j) find[gdirs[j]]=ind[j]; - // Current will be set equal to the start point for this grid index - addTaskToList( ingrid->getIndex(find) ); - } - // And prepare the task list - deactivateAllTasks(); - for(unsigned i=0;i<getFullNumberOfTasks();++i) taskFlags[i]=1; - lockContributors(); - // Set the direction in which to look for the contour - direction.resize( ingrid->getDimension(), 0 ); - direction[dir_n] = 0.999999999*ingrid->getGridSpacing()[dir_n]; + if( firsttime ) { + std::vector<unsigned> find( ingrid->getDimension() ); + std::vector<unsigned> ind( mygrid->getDimension() ); + for(unsigned i=0; i<mygrid->getNumberOfPoints(); ++i) { + find.assign( find.size(), 0 ); mygrid->getIndices( i, ind ); + for(unsigned j=0; j<gdirs.size(); ++j) find[gdirs[j]]=ind[j]; + // Current will be set equal to the start point for this grid index + addTaskToList( ingrid->getIndex(find) ); + } + // And prepare the task list + deactivateAllTasks(); + for(unsigned i=0; i<getFullNumberOfTasks(); ++i) taskFlags[i]=1; + lockContributors(); + // Set the direction in which to look for the contour + direction.resize( ingrid->getDimension(), 0 ); + direction[dir_n] = 0.999999999*ingrid->getGridSpacing()[dir_n]; } } -void FindContourSurface::finishAveraging(){ +void FindContourSurface::finishAveraging() { ContourFindingBase::finishAveraging(); // And update the list of active grid points - if( gbuffer>0 ){ - std::vector<double> dx( ingrid->getGridSpacing() ); - std::vector<double> point( ingrid->getDimension() ); - std::vector<double> lpoint( mygrid->getDimension() ); - std::vector<unsigned> neighbours; unsigned num_neighbours; - std::vector<unsigned> ugrid_indices( ingrid->getDimension() ); - std::vector<bool> active( ingrid->getNumberOfPoints(), false ); - std::vector<unsigned> gbuffer_vec( ingrid->getDimension(), gbuffer ); - for(unsigned i=0;i<mygrid->getNumberOfPoints();++i){ - // Retrieve the coordinates of this grid point - mygrid->getGridPointCoordinates( i, lpoint ); - point[dir_n] = mygrid->getGridElement( i, 0 ); - // 0.5*dx added here to prevent problems with flooring of grid points - for(unsigned j=0;j<gdirs.size();++j) point[gdirs[j]]=lpoint[j] + 0.5*dx[gdirs[j]]; - ingrid->getIndices( point, ugrid_indices ); - // Now activate buffer region - ingrid->getNeighbors( ugrid_indices , gbuffer_vec, num_neighbours, neighbours ); - for(unsigned n=0;n<num_neighbours;++n) active[ neighbours[n] ]=true; - } - ingrid->activateThesePoints( active ); + if( gbuffer>0 ) { + std::vector<double> dx( ingrid->getGridSpacing() ); + std::vector<double> point( ingrid->getDimension() ); + std::vector<double> lpoint( mygrid->getDimension() ); + std::vector<unsigned> neighbours; unsigned num_neighbours; + std::vector<unsigned> ugrid_indices( ingrid->getDimension() ); + std::vector<bool> active( ingrid->getNumberOfPoints(), false ); + std::vector<unsigned> gbuffer_vec( ingrid->getDimension(), gbuffer ); + for(unsigned i=0; i<mygrid->getNumberOfPoints(); ++i) { + // Retrieve the coordinates of this grid point + mygrid->getGridPointCoordinates( i, lpoint ); + point[dir_n] = mygrid->getGridElement( i, 0 ); + // 0.5*dx added here to prevent problems with flooring of grid points + for(unsigned j=0; j<gdirs.size(); ++j) point[gdirs[j]]=lpoint[j] + 0.5*dx[gdirs[j]]; + ingrid->getIndices( point, ugrid_indices ); + // Now activate buffer region + ingrid->getNeighbors( ugrid_indices, gbuffer_vec, num_neighbours, neighbours ); + for(unsigned n=0; n<num_neighbours; ++n) active[ neighbours[n] ]=true; + } + ingrid->activateThesePoints( active ); } firsttime=false; } @@ -212,51 +212,51 @@ void FindContourSurface::compute( const unsigned& current, MultiValue& myvals ) std::vector<unsigned> neighbours; unsigned num_neighbours; unsigned nfound=0; double minv=0, minp; std::vector<unsigned> bins_n( ingrid->getNbin() ); unsigned shiftn=current; std::vector<unsigned> ind( ingrid->getDimension() ); std::vector<double> point( ingrid->getDimension() ); -#ifndef DNDEBUG - std::vector<unsigned> oind( mygrid->getDimension() ); mygrid->getIndices( current, oind ); +#ifndef DNDEBUG + std::vector<unsigned> oind( mygrid->getDimension() ); mygrid->getIndices( current, oind ); #endif - for(unsigned i=0;i<bins_n[dir_n];++i){ + for(unsigned i=0; i<bins_n[dir_n]; ++i) { #ifndef DNDEBUG - std::vector<unsigned> base_ind( ingrid->getDimension() ); ingrid->getIndices( shiftn, base_ind ); - for(unsigned j=0;j<gdirs.size();++j) plumed_dbg_assert( base_ind[gdirs[j]]==oind[j] ); + std::vector<unsigned> base_ind( ingrid->getDimension() ); ingrid->getIndices( shiftn, base_ind ); + for(unsigned j=0; j<gdirs.size(); ++j) plumed_dbg_assert( base_ind[gdirs[j]]==oind[j] ); #endif - // Ensure inactive grid points are ignored - if( ingrid->inactive( shiftn ) ){ shiftn += ingrid->getStride()[dir_n]; continue; } - // Get the index of the current grid point - ingrid->getIndices( shiftn, ind ); - // Exit if we are at the edge of the grid - if( !ingrid->isPeriodic(dir_n) && (ind[dir_n]+1)==bins_n[dir_n] ){ - shiftn += ingrid->getStride()[dir_n]; continue; - } - - // Ensure points with inactive neighbours are ignored - ingrid->getNeighbors( ind, ones, num_neighbours, neighbours ); - bool cycle=false; - for(unsigned j=0;j<num_neighbours;++j){ - if( ingrid->inactive( neighbours[j]) ){ cycle=true; break; } - } - if( cycle ){ shiftn += ingrid->getStride()[dir_n]; continue; } - - // Now get the function value at two points - double val1=getFunctionValue( shiftn ) - contour; double val2; - if( (ind[dir_n]+1)==bins_n[dir_n] ) val2 = getFunctionValue( current ) - contour; - else val2=getFunctionValue( shiftn + ingrid->getStride()[dir_n] ) - contour; - - // Check if the minimum is bracketed - if( val1*val2<0 ){ - ingrid->getGridPointCoordinates( shiftn, point ); findContour( direction, point ); - minp=point[dir_n]; nfound++; break; - } - - - // This moves us on to the next point - shiftn += ingrid->getStride()[dir_n]; + // Ensure inactive grid points are ignored + if( ingrid->inactive( shiftn ) ) { shiftn += ingrid->getStride()[dir_n]; continue; } + // Get the index of the current grid point + ingrid->getIndices( shiftn, ind ); + // Exit if we are at the edge of the grid + if( !ingrid->isPeriodic(dir_n) && (ind[dir_n]+1)==bins_n[dir_n] ) { + shiftn += ingrid->getStride()[dir_n]; continue; + } + + // Ensure points with inactive neighbours are ignored + ingrid->getNeighbors( ind, ones, num_neighbours, neighbours ); + bool cycle=false; + for(unsigned j=0; j<num_neighbours; ++j) { + if( ingrid->inactive( neighbours[j]) ) { cycle=true; break; } + } + if( cycle ) { shiftn += ingrid->getStride()[dir_n]; continue; } + + // Now get the function value at two points + double val1=getFunctionValue( shiftn ) - contour; double val2; + if( (ind[dir_n]+1)==bins_n[dir_n] ) val2 = getFunctionValue( current ) - contour; + else val2=getFunctionValue( shiftn + ingrid->getStride()[dir_n] ) - contour; + + // Check if the minimum is bracketed + if( val1*val2<0 ) { + ingrid->getGridPointCoordinates( shiftn, point ); findContour( direction, point ); + minp=point[dir_n]; nfound++; break; + } + + + // This moves us on to the next point + shiftn += ingrid->getStride()[dir_n]; } - if( nfound==0 ){ - std::string num; Tools::convert( getStep(), num ); - error("On step " + num + " failed to find required grid point"); + if( nfound==0 ) { + std::string num; Tools::convert( getStep(), num ); + error("On step " + num + " failed to find required grid point"); } - myvals.setValue( 1, minp ); + myvals.setValue( 1, minp ); } } diff --git a/src/gridtools/FindSphericalContour.cpp b/src/gridtools/FindSphericalContour.cpp index 5d99abeda..a2ee2aa86 100644 --- a/src/gridtools/FindSphericalContour.cpp +++ b/src/gridtools/FindSphericalContour.cpp @@ -27,59 +27,59 @@ /* Find an isocontour in a three dimensional grid by searching over a Fibonacci sphere. -As discussed in the part of the manual on \ref Analysis PLUMED contains a number of tools that allow you to calculate -a function on a grid. The function on this grid might be a \ref HISTOGRAM as a function of a few collective variables +As discussed in the part of the manual on \ref Analysis PLUMED contains a number of tools that allow you to calculate +a function on a grid. The function on this grid might be a \ref HISTOGRAM as a function of a few collective variables or it might be a phase field that has been calcualted using \ref MULTICOLVARDENS. If this function has one or two input -arguments it is relatively straightforward to plot the function. If by contrast the data has a three dimensions it can be +arguments it is relatively straightforward to plot the function. If by contrast the data has a three dimensions it can be difficult to visualize. -This action provides one tool for visualizing these functions. It can be used to search for a set of points on a contour -wher the function takes a particular value. In other words, for the function \f$f(x,y,z)\f$ this action would find a set +This action provides one tool for visualizing these functions. It can be used to search for a set of points on a contour +wher the function takes a particular value. In other words, for the function \f$f(x,y,z)\f$ this action would find a set of points \f$\{x_c,y_c,z_c\}\f$ that have: \f[ f(x_c,y_c,z_c) - c = 0 \f] -where \f$c\f$ is some constant value that is specified by the user. The points on this contour are find by searching along a -set of equally spaced radii of a sphere that centered at on particular, user-speciified atom or virtual atom. To ensure that -these search radii are equally spaced on the surface of the sphere the search directions are generated by using a fibonacci +where \f$c\f$ is some constant value that is specified by the user. The points on this contour are find by searching along a +set of equally spaced radii of a sphere that centered at on particular, user-speciified atom or virtual atom. To ensure that +these search radii are equally spaced on the surface of the sphere the search directions are generated by using a fibonacci spiral projected on a sphere. In other words, the search directions are given by: \f[ -\mathbf{r}_i = \left( +\mathbf{r}_i = \left( \begin{matrix} \sqrt{1 - y^2} \cos(\phi) \\ \frac{2i}{n} - 1 + \frac{1}{n} \\ \sqrt{1 - y^2} \sin(\phi) -\end{matrix} +\end{matrix} \right) \f] -where \f$y\f$ is the quantity second component of the vector defined above, \f$n\f$ is the number of directions to look in and \f$\phi\f$ is +where \f$y\f$ is the quantity second component of the vector defined above, \f$n\f$ is the number of directions to look in and \f$\phi\f$ is \f[ \phi = \mod(i + R, n) \pi ( 3 - \sqrt{5} ) \f] -where \f$R\f$ is a random variable between 0 and \f$n-1\f$ that is generated during the read in of the input file and that is fixed during -the whole calculation. +where \f$R\f$ is a random variable between 0 and \f$n-1\f$ that is generated during the read in of the input file and that is fixed during +the whole calculation. -It is important to note that this action can only be used to detect countours in three dimensional functions. In addition, this action will fail to -find the full set of contour points if the contour does not have the same topology as a sphere. If you are uncertain that the isocontours in your -function have a spherical topology you should use \ref FIND_CONTOUR in place of \ref FIND_SPHERICAL_CONTOUR. +It is important to note that this action can only be used to detect countours in three dimensional functions. In addition, this action will fail to +find the full set of contour points if the contour does not have the same topology as a sphere. If you are uncertain that the isocontours in your +function have a spherical topology you should use \ref FIND_CONTOUR in place of \ref FIND_SPHERICAL_CONTOUR. \par Examples -The following input demonstrates how this action can be used. The input here is used to study the shape of a droplet that has been formed during the +The following input demonstrates how this action can be used. The input here is used to study the shape of a droplet that has been formed during the condensation of Lennard Jones from the vapour. The input below achieves this by calculating the coordination numbers of all the atoms within the gas. Obviously, those atoms within the droplet will have a large value for the coordination number while the isolated atoms in the gas will have a low value. As such we can detect the sizes of the droplets by constructing a \ref CONTACT_MATRIX whose \f$ij\f$ element tells us whether atom \f$i\f$ and atom \f$j\f$ -have coordination number that is greater that two. The atoms within the various droplets within the system can then be found by performing a +have coordination number that is greater that two. The atoms within the various droplets within the system can then be found by performing a \ref DFSCLUSTERING on this matrix to detect the connected components. We can take the largest of these connected components and find the center of the droplet -by exploiting the functionality within \ref CENTER_OF_MULTICOLVAR. We can then construct a phase field based on the positions of the atoms in the largest +by exploiting the functionality within \ref CENTER_OF_MULTICOLVAR. We can then construct a phase field based on the positions of the atoms in the largest cluster and the values of the coordination numbers of these atoms. The final line in the input then finds the a set of points on the dividing surface that separates -teh droplet from the surrounding gas. The value of the phase field on this isocontour is equal to 0.75. +teh droplet from the surrounding gas. The value of the phase field on this isocontour is equal to 0.75. \verbatim # Calculate coordination numbers @@ -119,7 +119,7 @@ public: PLUMED_REGISTER_ACTION(FindSphericalContour,"FIND_SPHERICAL_CONTOUR") -void FindSphericalContour::registerKeywords( Keywords& keys ){ +void FindSphericalContour::registerKeywords( Keywords& keys ) { ContourFindingBase::registerKeywords( keys ); keys.add("compulsory","NPOINTS","the number of points for which we are looking for the contour"); keys.add("compulsory","INNER_RADIUS","the minimum radius on which to look for the contour"); @@ -128,8 +128,8 @@ void FindSphericalContour::registerKeywords( Keywords& keys ){ } FindSphericalContour::FindSphericalContour(const ActionOptions&ao): -Action(ao), -ContourFindingBase(ao) + Action(ao), + ContourFindingBase(ao) { if( ingrid->getDimension()!=3 ) error("input grid must be three dimensional"); @@ -145,9 +145,9 @@ ContourFindingBase(ao) checkRead(); // Create a task list - for(unsigned i=0;i<npoints;++i) addTaskToList( i ); + for(unsigned i=0; i<npoints; ++i) addTaskToList( i ); deactivateAllTasks(); - for(unsigned i=0;i<getFullNumberOfTasks();++i) taskFlags[i]=1; + for(unsigned i=0; i<getFullNumberOfTasks(); ++i) taskFlags[i]=1; lockContributors(); } @@ -157,22 +157,22 @@ void FindSphericalContour::compute( const unsigned& current, MultiValue& myvals // Retrieve this contour point from grid mygrid->getGridPointCoordinates( current, direction ); // Now setup contour point on inner sphere - for(unsigned j=0;j<3;++j){ - contour_point[j] = min*direction[j]; - direction[j] = (max-min)*direction[j] / static_cast<double>(nbins); + for(unsigned j=0; j<3; ++j) { + contour_point[j] = min*direction[j]; + direction[j] = (max-min)*direction[j] / static_cast<double>(nbins); } bool found=false; - for(unsigned k=0;k<nbins;++k){ - for(unsigned j=0;j<3;++j) tmp[j] = contour_point[j] + direction[j]; - double val1 = getDifferenceFromContour( contour_point, der ); - double val2 = getDifferenceFromContour( tmp, der ); - if( val1*val2<0 ){ - findContour( direction, contour_point ); - double norm=0; for(unsigned j=0;j<3;++j) norm += contour_point[j]*contour_point[j]; - myvals.setValue( 1, sqrt(norm) ); found=true; break; - } - for(unsigned j=0;j<3;++j) contour_point[j] = tmp[j]; - } + for(unsigned k=0; k<nbins; ++k) { + for(unsigned j=0; j<3; ++j) tmp[j] = contour_point[j] + direction[j]; + double val1 = getDifferenceFromContour( contour_point, der ); + double val2 = getDifferenceFromContour( tmp, der ); + if( val1*val2<0 ) { + findContour( direction, contour_point ); + double norm=0; for(unsigned j=0; j<3; ++j) norm += contour_point[j]*contour_point[j]; + myvals.setValue( 1, sqrt(norm) ); found=true; break; + } + for(unsigned j=0; j<3; ++j) contour_point[j] = tmp[j]; + } if( !found ) error("range does not bracket the dividing surface"); } diff --git a/src/gridtools/FourierTransform.cpp b/src/gridtools/FourierTransform.cpp index 15651b304..5a53b390d 100644 --- a/src/gridtools/FourierTransform.cpp +++ b/src/gridtools/FourierTransform.cpp @@ -64,7 +64,7 @@ FOURIER_TRANSFORM STRIDE=1 GRID=density FT_TYPE=complex FOURIER_PARAMETERS=0,-1 */ //+ENDPLUMEDOC - + class FourierTransform : public ActionWithInputGrid { private: std::string output_type; @@ -73,32 +73,32 @@ private: std::vector<int> fourier_params; public: static void registerKeywords( Keywords& keys ); - explicit FourierTransform(const ActionOptions&ao); + explicit FourierTransform(const ActionOptions&ao); #ifndef __PLUMED_HAS_FFTW - void performOperations( const bool& from_update ){} + void performOperations( const bool& from_update ) {} #else void performOperations( const bool& from_update ); #endif - void compute( const unsigned& , MultiValue& ) const {} - bool isPeriodic(){ return false; } + void compute( const unsigned&, MultiValue& ) const {} + bool isPeriodic() { return false; } }; PLUMED_REGISTER_ACTION(FourierTransform,"FOURIER_TRANSFORM") -void FourierTransform::registerKeywords( Keywords& keys ){ +void FourierTransform::registerKeywords( Keywords& keys ) { ActionWithInputGrid::registerKeywords( keys ); keys.remove("BANDWIDTH"); keys.remove("KERNEL"); keys.add("optional","FT_TYPE","choose what kind of data you want as output on the grid. Possible values are: ABS = compute the complex modulus of Fourier coefficients (DEFAULT); NORM = compute the norm (i.e. ABS^2) of Fourier coefficients; COMPLEX = store the FFTW complex output on the grid (as a vector)."); keys.add("compulsory","FOURIER_PARAMETERS","default","what kind of normalization is applied to the output and if the Fourier transform in FORWARD or BACKWARD. This keyword takes the form FOURIER_PARAMETERS=A,B, where A and B can be 0, 1 or -1. The default values are A=1 (no normalization at all) and B=1 (forward FFT). Other possible choices for A are: " - "A=-1: normalize by the number of data, " - "A=0: normalize by the square root of the number of data (one forward and followed by backward FFT recover the original data). "); + "A=-1: normalize by the number of data, " + "A=0: normalize by the square root of the number of data (one forward and followed by backward FFT recover the original data). "); } FourierTransform::FourierTransform(const ActionOptions&ao): -Action(ao), -ActionWithInputGrid(ao), -real_output(true), -store_norm(false), -fourier_params(2) + Action(ao), + ActionWithInputGrid(ao), + real_output(true), + store_norm(false), + fourier_params(2) { #ifndef __PLUMED_HAS_FFTW error("this feature is only available if you compile PLUMED with FFTW"); @@ -108,58 +108,58 @@ fourier_params(2) // Get the type of FT parse("FT_TYPE",output_type); if (output_type.length()==0) { - log<<" keyword FT_TYPE unset. By default output grid will contain REAL Fourier coefficients\n"; + log<<" keyword FT_TYPE unset. By default output grid will contain REAL Fourier coefficients\n"; } else if ( output_type=="ABS" || output_type=="abs") { - log << " keyword FT_TYPE is '"<< output_type << "' : will compute the MODULUS of Fourier coefficients\n"; + log << " keyword FT_TYPE is '"<< output_type << "' : will compute the MODULUS of Fourier coefficients\n"; } else if ( output_type=="NORM" || output_type=="norm") { - log << " keyword FT_TYPE is '"<< output_type << "' : will compute the NORM of Fourier coefficients\n"; - store_norm=true; + log << " keyword FT_TYPE is '"<< output_type << "' : will compute the NORM of Fourier coefficients\n"; + store_norm=true; } else if ( output_type=="COMPLEX" || output_type=="complex" ) { - log<<" keyword FT_TYPE is '"<< output_type <<"' : output grid will contain the COMPLEX Fourier coefficients\n"; - real_output=false; + log<<" keyword FT_TYPE is '"<< output_type <<"' : output grid will contain the COMPLEX Fourier coefficients\n"; + real_output=false; } else error("keyword FT_TYPE unrecognized!"); // Normalize output? std::string params_str; parse("FOURIER_PARAMETERS",params_str); if (params_str=="default") { - fourier_params.assign( fourier_params.size(), 1 ); - log.printf(" default values of Fourier parameters A=%i, B=%i : the output will NOT be normalized and BACKWARD Fourier transform is computed \n", fourier_params[0],fourier_params[1]); + fourier_params.assign( fourier_params.size(), 1 ); + log.printf(" default values of Fourier parameters A=%i, B=%i : the output will NOT be normalized and BACKWARD Fourier transform is computed \n", fourier_params[0],fourier_params[1]); } else { - std::vector<std::string> fourier_str = Tools::getWords(params_str, "\t\n ,"); - if (fourier_str.size()>2) error("FOURIER_PARAMETERS can take just two values"); - for (unsigned i=0; i<fourier_str.size(); ++i) { - Tools::convert(fourier_str[i],fourier_params[i]); - if (fourier_params[i]>1 || fourier_params[i]<-1) error("values accepted for FOURIER_PARAMETERS are only -1, 1 or 0"); - } - log.printf(" Fourier parameters are A=%i, B=%i \n", fourier_params[0],fourier_params[1]); + std::vector<std::string> fourier_str = Tools::getWords(params_str, "\t\n ,"); + if (fourier_str.size()>2) error("FOURIER_PARAMETERS can take just two values"); + for (unsigned i=0; i<fourier_str.size(); ++i) { + Tools::convert(fourier_str[i],fourier_params[i]); + if (fourier_params[i]>1 || fourier_params[i]<-1) error("values accepted for FOURIER_PARAMETERS are only -1, 1 or 0"); + } + log.printf(" Fourier parameters are A=%i, B=%i \n", fourier_params[0],fourier_params[1]); } // Create the input from the old string std::string vstring; unsigned n=0; gdirs.resize( ingrid->getDimension() ); - for(unsigned i=0;i<ingrid->getDimension();++i){ - gdirs[n]=i; n++; + for(unsigned i=0; i<ingrid->getDimension(); ++i) { + gdirs[n]=i; n++; } - + plumed_assert( n==ingrid->getDimension() ); - - if (real_output) { - if (!store_norm) vstring="COMPONENTS=" + getLabel() + "_abs"; - else vstring="COMPONENTS=" + getLabel() + "_norm"; + + if (real_output) { + if (!store_norm) vstring="COMPONENTS=" + getLabel() + "_abs"; + else vstring="COMPONENTS=" + getLabel() + "_norm"; } else vstring="COMPONENTS=" + getLabel() + "_real," + getLabel() + "_imag"; - + // Set COORDINATES keyword vstring += " COORDINATES=" + ingrid->getComponentName( gdirs[0] ); for(unsigned i=1; i<gdirs.size(); ++i) vstring += "," + ingrid->getComponentName( gdirs[i] ); - + // Set PBC keyword vstring += " PBC="; if( ingrid->isPeriodic(gdirs[0]) ) vstring+="T"; else vstring+="F"; - for(unsigned i=1; i<gdirs.size(); ++i){ - if( ingrid->isPeriodic(gdirs[i]) ) vstring+=",T"; else vstring+=",F"; + for(unsigned i=1; i<gdirs.size(); ++i) { + if( ingrid->isPeriodic(gdirs[i]) ) vstring+=",T"; else vstring+=",F"; } - + // Create a grid on which to store the fourier transform of the input grid createGrid( "grid", vstring ); @@ -171,97 +171,97 @@ fourier_params(2) } #ifdef __PLUMED_HAS_FFTW -void FourierTransform::performOperations( const bool& from_update ){ - - // Spacing of the real grid - std::vector<double> g_spacing ( ingrid->getGridSpacing() ); - // Spacing of the k-grid - std::vector<double> ft_spacing; - // Extents of the k-grid - std::vector<std::string> ft_min( ingrid->getMin() ), ft_max( ingrid->getMax() ); - // Number of bins in the k-grid (equal to the number of bins in the real grid) - std::vector<unsigned> ft_bins ( ingrid->getNbin() ); - - for (unsigned i=0; i<ingrid->getDimension(); ++i) { - // Check PBC in current grid dimension - if( !ingrid->isPeriodic(i) ) ft_bins[i]++; - // Compute k-grid extents - double dmin, dmax; - Tools::convert(ft_min[i],dmin); Tools::convert(ft_max[i],dmax); - // We want to have the min of k-grid at point (0,0) - dmin=0.0; - dmax=2.0*pi*ft_bins[i]/( ingrid->getGridExtent(i) ); - Tools::convert(dmin,ft_min[i]); Tools::convert(dmax,ft_max[i]); - } - - // This is the actual setup of the k-grid - mygrid->setBounds( ft_min, ft_max, ft_bins, ft_spacing); resizeFunctions(); - - // *** CHECK CORRECT k-GRID BOUNDARIES *** - //log<<"Real grid boundaries: \n" - // <<" min_x: "<<mygrid->getMin()[0]<<" min_y: "<<mygrid->getMin()[1]<<"\n" - // <<" max_x: "<<mygrid->getMax()[0]<<" max_y: "<<mygrid->getMax()[1]<<"\n" - // <<"K-grid boundaries:"<<"\n" - // <<" min_x: "<<ft_min[0]<<" min_y: "<<ft_min[1]<<"\n" - // <<" max_x: "<<ft_max[0]<<" max_y: "<<ft_max[1]<<"\n"; - - - - // Get the size of the input data arrays (to allocate FFT data) - std::vector<unsigned> N_input_data( ingrid->getNbin() ); - size_t fft_dimension=1; for(unsigned i=0; i<N_input_data.size(); ++i) fft_dimension*=static_cast<size_t>( N_input_data[i] ); - - // FFT arrays - std::vector<std::complex<double> > input_data(fft_dimension), fft_data(fft_dimension); - - - // Fill real input with the data on the grid - std::vector<unsigned> ind( ingrid->getDimension() ); - for (unsigned i=0;i<ingrid->getNumberOfPoints();++i) { - // Get point indices - ingrid->getIndices(i, ind); - // Fill input data in row-major order - input_data[ind[0]*N_input_data[0]+ind[1]].real( getFunctionValue( i ) ); - input_data[ind[0]*N_input_data[0]+ind[1]].imag( 0.0 ); - } +void FourierTransform::performOperations( const bool& from_update ) { + + // Spacing of the real grid + std::vector<double> g_spacing ( ingrid->getGridSpacing() ); + // Spacing of the k-grid + std::vector<double> ft_spacing; + // Extents of the k-grid + std::vector<std::string> ft_min( ingrid->getMin() ), ft_max( ingrid->getMax() ); + // Number of bins in the k-grid (equal to the number of bins in the real grid) + std::vector<unsigned> ft_bins ( ingrid->getNbin() ); + + for (unsigned i=0; i<ingrid->getDimension(); ++i) { + // Check PBC in current grid dimension + if( !ingrid->isPeriodic(i) ) ft_bins[i]++; + // Compute k-grid extents + double dmin, dmax; + Tools::convert(ft_min[i],dmin); Tools::convert(ft_max[i],dmax); + // We want to have the min of k-grid at point (0,0) + dmin=0.0; + dmax=2.0*pi*ft_bins[i]/( ingrid->getGridExtent(i) ); + Tools::convert(dmin,ft_min[i]); Tools::convert(dmax,ft_max[i]); + } + + // This is the actual setup of the k-grid + mygrid->setBounds( ft_min, ft_max, ft_bins, ft_spacing); resizeFunctions(); + + // *** CHECK CORRECT k-GRID BOUNDARIES *** + //log<<"Real grid boundaries: \n" + // <<" min_x: "<<mygrid->getMin()[0]<<" min_y: "<<mygrid->getMin()[1]<<"\n" + // <<" max_x: "<<mygrid->getMax()[0]<<" max_y: "<<mygrid->getMax()[1]<<"\n" + // <<"K-grid boundaries:"<<"\n" + // <<" min_x: "<<ft_min[0]<<" min_y: "<<ft_min[1]<<"\n" + // <<" max_x: "<<ft_max[0]<<" max_y: "<<ft_max[1]<<"\n"; - // *** HERE is the only clear limitation: I'm computing explicitly a 2D FT. It should not happen to deal with other than two-dimensional grid ... - fftw_plan plan_complex = fftw_plan_dft_2d(N_input_data[0], N_input_data[1], reinterpret_cast<fftw_complex*>(&input_data[0]), reinterpret_cast<fftw_complex*>(&fft_data[0]), fourier_params[1], FFTW_ESTIMATE); - - // Compute FT - fftw_execute( plan_complex ); - // Compute the normalization constant - double norm=1.0; - for (unsigned i=0; i<N_input_data.size(); ++i) { - norm *= pow( N_input_data[i], (1-fourier_params[0])/2 ); - } - // Save FT data to output grid - std::vector<unsigned> N_out_data ( mygrid->getNbin() ); - std::vector<unsigned> out_ind ( mygrid->getDimension() ); - for(unsigned i=0; i<mygrid->getNumberOfPoints(); ++i){ - mygrid->getIndices( i, out_ind ); - if (real_output) { - double ft_value; - // Compute abs/norm and fix normalization - if (!store_norm) ft_value=std::abs( fft_data[out_ind[0]*N_out_data[0]+out_ind[1]] / norm ); - else ft_value=std::norm( fft_data[out_ind[0]*N_out_data[0]+out_ind[1]] / norm ); - // Set the value - mygrid->setGridElement( i, 0, ft_value ); - } else { - double ft_value_real, ft_value_imag; - ft_value_real=fft_data[out_ind[0]*N_out_data[0]+out_ind[1]].real() / norm; - ft_value_imag=fft_data[out_ind[0]*N_out_data[0]+out_ind[1]].imag() / norm; - // Set values - mygrid->setGridElement( i, 0, ft_value_real); - mygrid->setGridElement( i, 1, ft_value_imag); - } + // Get the size of the input data arrays (to allocate FFT data) + std::vector<unsigned> N_input_data( ingrid->getNbin() ); + size_t fft_dimension=1; for(unsigned i=0; i<N_input_data.size(); ++i) fft_dimension*=static_cast<size_t>( N_input_data[i] ); + + // FFT arrays + std::vector<std::complex<double> > input_data(fft_dimension), fft_data(fft_dimension); + + + // Fill real input with the data on the grid + std::vector<unsigned> ind( ingrid->getDimension() ); + for (unsigned i=0; i<ingrid->getNumberOfPoints(); ++i) { + // Get point indices + ingrid->getIndices(i, ind); + // Fill input data in row-major order + input_data[ind[0]*N_input_data[0]+ind[1]].real( getFunctionValue( i ) ); + input_data[ind[0]*N_input_data[0]+ind[1]].imag( 0.0 ); + } + + // *** HERE is the only clear limitation: I'm computing explicitly a 2D FT. It should not happen to deal with other than two-dimensional grid ... + fftw_plan plan_complex = fftw_plan_dft_2d(N_input_data[0], N_input_data[1], reinterpret_cast<fftw_complex*>(&input_data[0]), reinterpret_cast<fftw_complex*>(&fft_data[0]), fourier_params[1], FFTW_ESTIMATE); + + // Compute FT + fftw_execute( plan_complex ); + + // Compute the normalization constant + double norm=1.0; + for (unsigned i=0; i<N_input_data.size(); ++i) { + norm *= pow( N_input_data[i], (1-fourier_params[0])/2 ); + } + + // Save FT data to output grid + std::vector<unsigned> N_out_data ( mygrid->getNbin() ); + std::vector<unsigned> out_ind ( mygrid->getDimension() ); + for(unsigned i=0; i<mygrid->getNumberOfPoints(); ++i) { + mygrid->getIndices( i, out_ind ); + if (real_output) { + double ft_value; + // Compute abs/norm and fix normalization + if (!store_norm) ft_value=std::abs( fft_data[out_ind[0]*N_out_data[0]+out_ind[1]] / norm ); + else ft_value=std::norm( fft_data[out_ind[0]*N_out_data[0]+out_ind[1]] / norm ); + // Set the value + mygrid->setGridElement( i, 0, ft_value ); + } else { + double ft_value_real, ft_value_imag; + ft_value_real=fft_data[out_ind[0]*N_out_data[0]+out_ind[1]].real() / norm; + ft_value_imag=fft_data[out_ind[0]*N_out_data[0]+out_ind[1]].imag() / norm; + // Set values + mygrid->setGridElement( i, 0, ft_value_real); + mygrid->setGridElement( i, 1, ft_value_imag); } - - // Free FFTW stuff - fftw_destroy_plan(plan_complex); - + } + + // Free FFTW stuff + fftw_destroy_plan(plan_complex); + } #endif diff --git a/src/gridtools/GridPrintingBase.cpp b/src/gridtools/GridPrintingBase.cpp index 90bf94973..616284d45 100644 --- a/src/gridtools/GridPrintingBase.cpp +++ b/src/gridtools/GridPrintingBase.cpp @@ -27,42 +27,42 @@ namespace PLMD { namespace gridtools { -void GridPrintingBase::registerKeywords( Keywords& keys ){ +void GridPrintingBase::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionPilot::registerKeywords( keys ); keys.add("compulsory","GRID","the action that creates the grid you would like to output"); keys.add("compulsory","STRIDE","0","the frequency with which the grid should be output to the file. The default " - "value of 0 ensures that the grid is only output at the end of the trajectory"); + "value of 0 ensures that the grid is only output at the end of the trajectory"); keys.add("compulsory","FILE","density","the file on which to write the grid."); keys.add("optional","FMT","the format that should be used to output real numbers"); } GridPrintingBase::GridPrintingBase(const ActionOptions&ao): -Action(ao), -ActionPilot(ao), -fmt("%f") + Action(ao), + ActionPilot(ao), + fmt("%f") { std::string mlab; parse("GRID",mlab); vesselbase::ActionWithVessel* mves= plumed.getActionSet().selectWithLabel<vesselbase::ActionWithVessel*>(mlab); if(!mves) error("action labelled " + mlab + " does not exist or does not have vessels"); addDependency(mves); - for(unsigned i=0;i<mves->getNumberOfVessels();++i){ - ingrid=dynamic_cast<GridVessel*>( mves->getPntrToVessel(i) ); - if( ingrid ) break; + for(unsigned i=0; i<mves->getNumberOfVessels(); ++i) { + ingrid=dynamic_cast<GridVessel*>( mves->getPntrToVessel(i) ); + if( ingrid ) break; } if( !ingrid ) error("input action does not calculate a grid"); - parse("FILE",filename); + parse("FILE",filename); if(filename.length()==0) error("name out output file was not specified"); log.printf(" outputting grid calculated by action %s to file named %s",mves->getLabel().c_str(), filename.c_str() ); - if( keywords.exists("FMT") ){ - parse("FMT",fmt); log.printf(" with format %s \n", fmt.c_str() ); + if( keywords.exists("FMT") ) { + parse("FMT",fmt); log.printf(" with format %s \n", fmt.c_str() ); } else { - log.printf("\n"); + log.printf("\n"); } } -void GridPrintingBase::update(){ +void GridPrintingBase::update() { if( getStep()==0 || getStride()==0 ) return ; OFile ofile; ofile.link(*this); @@ -70,7 +70,7 @@ void GridPrintingBase::update(){ ofile.open( filename ); printGrid( ofile ); ofile.close(); } -void GridPrintingBase::runFinalJobs(){ +void GridPrintingBase::runFinalJobs() { if( getStride()>0 ) return; OFile ofile; ofile.link(*this); diff --git a/src/gridtools/GridPrintingBase.h b/src/gridtools/GridPrintingBase.h index a9b79cd32..d33865d73 100644 --- a/src/gridtools/GridPrintingBase.h +++ b/src/gridtools/GridPrintingBase.h @@ -36,8 +36,8 @@ protected: public: static void registerKeywords( Keywords& keys ); explicit GridPrintingBase(const ActionOptions&ao); - void calculate(){} - void apply(){} + void calculate() {} + void apply() {} void update(); void runFinalJobs(); virtual void printGrid( OFile& ofile ) const=0; diff --git a/src/gridtools/GridToXYZ.cpp b/src/gridtools/GridToXYZ.cpp index 214e33903..75e508a3f 100644 --- a/src/gridtools/GridToXYZ.cpp +++ b/src/gridtools/GridToXYZ.cpp @@ -43,13 +43,13 @@ private: unsigned mycomp; public: static void registerKeywords( Keywords& keys ); - explicit GridToXYZ(const ActionOptions&ao); + explicit GridToXYZ(const ActionOptions&ao); void printGrid( OFile& ofile ) const ; }; PLUMED_REGISTER_ACTION(GridToXYZ,"GRID_TO_XYZ") -void GridToXYZ::registerKeywords( Keywords& keys ){ +void GridToXYZ::registerKeywords( Keywords& keys ) { GridPrintingBase::registerKeywords( keys ); keys.add("optional","COMPONENT","if your input is a vector field use this to specifiy the component of the input vector field for which you wish to output"); keys.add("compulsory","UNITS","PLUMED","the units in which to print out the coordinates. PLUMED means internal PLUMED units"); @@ -58,32 +58,32 @@ void GridToXYZ::registerKeywords( Keywords& keys ){ } GridToXYZ::GridToXYZ(const ActionOptions&ao): -Action(ao), -GridPrintingBase(ao) + Action(ao), + GridPrintingBase(ao) { if( ingrid->getDimension()!=3 ) error("cannot print grid xyz file if grid does not contain three dimensional data"); - fmt = " " + fmt; + fmt = " " + fmt; - if( ingrid->getNumberOfComponents()==1 ){ - mycomp=0; + if( ingrid->getNumberOfComponents()==1 ) { + mycomp=0; } else { - int tcomp=-1; parse("COMPONENT",tcomp); - if( tcomp<0 ) error("component of vector field was not specified - use COMPONENT keyword"); - mycomp=tcomp*(1+ingrid->getDimension()); if( ingrid->noDerivatives() ) mycomp=tcomp; - log.printf(" using %dth component of grid \n",tcomp ); + int tcomp=-1; parse("COMPONENT",tcomp); + if( tcomp<0 ) error("component of vector field was not specified - use COMPONENT keyword"); + mycomp=tcomp*(1+ingrid->getDimension()); if( ingrid->noDerivatives() ) mycomp=tcomp; + log.printf(" using %dth component of grid \n",tcomp ); } fmt="%f"; std::string precision; parse("PRECISION",precision); - if(precision.length()>0){ - int p; Tools::convert(precision,p); - log<<" with precision "<<p<<"\n"; - std::string a,b; - Tools::convert(p+5,a); - Tools::convert(p,b); - fmt="%"+a+"."+b+"f"; + if(precision.length()>0) { + int p; Tools::convert(precision,p); + log<<" with precision "<<p<<"\n"; + std::string a,b; + Tools::convert(p+5,a); + Tools::convert(p,b); + fmt="%"+a+"."+b+"f"; } std::string unitname; parse("UNITS",unitname); - if(unitname!="PLUMED"){ + if(unitname!="PLUMED") { Units myunit; myunit.setLength(unitname); lenunit=plumed.getAtoms().getUnits().getLength()/myunit.getLength(); } @@ -95,13 +95,13 @@ void GridToXYZ::printGrid( OFile& ofile ) const { std::vector<double> point( 3 ); double val; ofile.printf("%u\n",ingrid->getNumberOfPoints()); ofile.printf("Grid converted to xyz file \n"); - for(unsigned i=0;i<ingrid->getNumberOfPoints();++i){ - ingrid->getGridPointCoordinates( i, point ); - ofile.printf("X"); double val=ingrid->getGridElement( i, 0 ); - if( ingrid->getType()=="flat" ) val=1.0; - else val=ingrid->getGridElement( i, 0 ); - for(unsigned j=0;j<3;++j){ ofile.printf( (" " + fmt).c_str(), val*lenunit*point[j] ); } - ofile.printf("\n"); + for(unsigned i=0; i<ingrid->getNumberOfPoints(); ++i) { + ingrid->getGridPointCoordinates( i, point ); + ofile.printf("X"); double val=ingrid->getGridElement( i, 0 ); + if( ingrid->getType()=="flat" ) val=1.0; + else val=ingrid->getGridElement( i, 0 ); + for(unsigned j=0; j<3; ++j) { ofile.printf( (" " + fmt).c_str(), val*lenunit*point[j] ); } + ofile.printf("\n"); } } diff --git a/src/gridtools/GridVessel.cpp b/src/gridtools/GridVessel.cpp index f09e3f21a..5282667a4 100644 --- a/src/gridtools/GridVessel.cpp +++ b/src/gridtools/GridVessel.cpp @@ -27,7 +27,7 @@ namespace PLMD { namespace gridtools { -void GridVessel::registerKeywords( Keywords& keys ){ +void GridVessel::registerKeywords( Keywords& keys ) { AveragingVessel::registerKeywords( keys ); keys.add("compulsory","TYPE","flat","how the grid points are being generated"); keys.add("compulsory","COMPONENTS","the names of the components in the vector"); @@ -36,12 +36,12 @@ void GridVessel::registerKeywords( Keywords& keys ){ } GridVessel::GridVessel( const vesselbase::VesselOptions& da ): -AveragingVessel(da), -bounds_set(false), -cube_units(1.0), -noderiv(false), -npoints(0), -wasforced(false) + AveragingVessel(da), + bounds_set(false), + cube_units(1.0), + noderiv(false), + npoints(0), + wasforced(false) { std::string geom; parse("TYPE",geom); if( geom=="flat" ) gtype=flat; @@ -49,102 +49,102 @@ wasforced(false) else plumed_merror( geom + " is invalid geometry type"); std::vector<std::string> compnames; parseVector("COMPONENTS",compnames); std::vector<std::string> coordnames; parseVector("COORDINATES",coordnames); - if( gtype==flat ){ - dimension=coordnames.size(); - str_min.resize( dimension); str_max.resize( dimension ); stride.resize( dimension ); - max.resize( dimension ); dx.resize( dimension ); nbin.resize( dimension ); min.resize( dimension ); - } else if( gtype==fibonacci ){ - if( coordnames.size()!=3 ) error("cannot generate fibonacci grid points on surface of sphere if not 3 input coordinates"); - dimension=3; + if( gtype==flat ) { + dimension=coordnames.size(); + str_min.resize( dimension); str_max.resize( dimension ); stride.resize( dimension ); + max.resize( dimension ); dx.resize( dimension ); nbin.resize( dimension ); min.resize( dimension ); + } else if( gtype==fibonacci ) { + if( coordnames.size()!=3 ) error("cannot generate fibonacci grid points on surface of sphere if not 3 input coordinates"); + dimension=3; } unsigned n=0; nper=compnames.size()*( 1 + coordnames.size() ); arg_names.resize( coordnames.size() + compnames.size()*( 1 + coordnames.size() ) ); - for(unsigned i=0;i<coordnames.size();++i){ arg_names[n] = coordnames[i]; n++; } - for(unsigned i=0;i<compnames.size();++i){ - arg_names[n]=compnames[i]; n++; - for(unsigned j=0;j<coordnames.size();++j){ arg_names[n] = "d" + compnames[i] + "_" + coordnames[j]; n++; } + for(unsigned i=0; i<coordnames.size(); ++i) { arg_names[n] = coordnames[i]; n++; } + for(unsigned i=0; i<compnames.size(); ++i) { + arg_names[n]=compnames[i]; n++; + for(unsigned j=0; j<coordnames.size(); ++j) { arg_names[n] = "d" + compnames[i] + "_" + coordnames[j]; n++; } } pbc.resize( dimension ); std::vector<std::string> spbc( dimension ); parseVector("PBC",spbc); - for(unsigned i=0;i<dimension;++i){ - if( spbc[i]=="F" ) pbc[i]=false; - else if( spbc[i]=="T" ) pbc[i]=true; - else plumed_error(); + for(unsigned i=0; i<dimension; ++i) { + if( spbc[i]=="F" ) pbc[i]=false; + else if( spbc[i]=="T" ) pbc[i]=true; + else plumed_error(); } } -void GridVessel::setNoDerivatives(){ +void GridVessel::setNoDerivatives() { nper = ( nper/(1+dimension) ); noderiv=true; std::vector<std::string> tnames( dimension ), cnames(nper); - for(unsigned i=0;i<dimension;++i) tnames[i]=arg_names[i]; - unsigned k=dimension; for(unsigned i=0;i<nper;++i){ cnames[i]=arg_names[k]; k+=(1+dimension); } + for(unsigned i=0; i<dimension; ++i) tnames[i]=arg_names[i]; + unsigned k=dimension; for(unsigned i=0; i<nper; ++i) { cnames[i]=arg_names[k]; k+=(1+dimension); } arg_names.resize( dimension + nper ); - for(unsigned i=0;i<dimension;++i) arg_names[i]=tnames[i]; - for(unsigned i=0;i<nper;++i) arg_names[dimension+i]=cnames[i]; + for(unsigned i=0; i<dimension; ++i) arg_names[i]=tnames[i]; + for(unsigned i=0; i<nper; ++i) arg_names[dimension+i]=cnames[i]; } void GridVessel::setBounds( const std::vector<std::string>& smin, const std::vector<std::string>& smax, - const std::vector<unsigned>& binsin, const std::vector<double>& spacing ){ + const std::vector<unsigned>& binsin, const std::vector<double>& spacing ) { plumed_dbg_assert( smin.size()==dimension && smax.size()==dimension ); plumed_assert( gtype==flat && (spacing.size()==dimension || binsin.size()==dimension) ); npoints=1; bounds_set=true; - for(unsigned i=0;i<dimension;++i){ - str_min[i]=smin[i]; str_max[i]=smax[i]; - Tools::convert( str_min[i], min[i] ); - Tools::convert( str_max[i], max[i] ); - if( spacing.size()==dimension && binsin.size()==dimension ){ - double range = max[i] - min[i]; unsigned spc = std::floor( range / spacing[i]); - // This check ensures that nbins is set correctly if spacing is set the same as the number of bins - if( fabs( binsin[i]*spacing[i]-range )>epsilon ) spc += 1; - if( spc>binsin[i] ) nbin[i]=spc; else nbin[i]=binsin[i]; - } else if( binsin.size()==dimension ) nbin[i]=binsin[i]; - else if( spacing.size()==dimension ) nbin[i] = std::floor(( max[i] - min[i] ) / spacing[i]) + 1; - else plumed_error(); - dx[i] = ( max[i] - min[i] ) / static_cast<double>( nbin[i] ); - if( !pbc[i] ){ max[i] +=dx[i]; nbin[i]+=1; } - stride[i]=npoints; - npoints*=nbin[i]; + for(unsigned i=0; i<dimension; ++i) { + str_min[i]=smin[i]; str_max[i]=smax[i]; + Tools::convert( str_min[i], min[i] ); + Tools::convert( str_max[i], max[i] ); + if( spacing.size()==dimension && binsin.size()==dimension ) { + double range = max[i] - min[i]; unsigned spc = std::floor( range / spacing[i]); + // This check ensures that nbins is set correctly if spacing is set the same as the number of bins + if( fabs( binsin[i]*spacing[i]-range )>epsilon ) spc += 1; + if( spc>binsin[i] ) nbin[i]=spc; else nbin[i]=binsin[i]; + } else if( binsin.size()==dimension ) nbin[i]=binsin[i]; + else if( spacing.size()==dimension ) nbin[i] = std::floor(( max[i] - min[i] ) / spacing[i]) + 1; + else plumed_error(); + dx[i] = ( max[i] - min[i] ) / static_cast<double>( nbin[i] ); + if( !pbc[i] ) { max[i] +=dx[i]; nbin[i]+=1; } + stride[i]=npoints; + npoints*=nbin[i]; } - resize(); // Always resize after setting new bounds as grid size may have have changed -} + resize(); // Always resize after setting new bounds as grid size may have have changed +} -void GridVessel::setupFibonacciGrid( const unsigned& np ){ +void GridVessel::setupFibonacciGrid( const unsigned& np ) { bounds_set=true; npoints = np; fib_increment = pi*( 3 - sqrt(5) ); - fib_offset = 2 / static_cast<double>( npoints ); + fib_offset = 2 / static_cast<double>( npoints ); Random random; fib_rnd = std::floor( npoints*random.RandU01() ); resize(); } -std::string GridVessel::description(){ +std::string GridVessel::description() { if( !bounds_set ) return ""; - + std::string des; - if( gtype==flat ){ - des="grid of "; std::string num; - for(unsigned i=0;i<dimension-1;++i){ - Tools::convert( nbin[i], num ); - des += num + " X "; - } - Tools::convert( nbin[dimension-1], num ); - des += num + " equally spaced points between ("; - for(unsigned i=0;i<dimension-1;++i) des += str_min[i] + ","; - Tools::convert( nbin[dimension-1], num ); - des += str_min[dimension-1] + ") and ("; - for(unsigned i=0;i<dimension-1;++i) des += str_max[i] + ","; - des += str_max[dimension-1] + ")"; - } else if( gtype==fibonacci ){ - std::string num; Tools::convert( npoints, num ); - des += "fibonacci grid of " + num + " points on spherical surface"; + if( gtype==flat ) { + des="grid of "; std::string num; + for(unsigned i=0; i<dimension-1; ++i) { + Tools::convert( nbin[i], num ); + des += num + " X "; + } + Tools::convert( nbin[dimension-1], num ); + des += num + " equally spaced points between ("; + for(unsigned i=0; i<dimension-1; ++i) des += str_min[i] + ","; + Tools::convert( nbin[dimension-1], num ); + des += str_min[dimension-1] + ") and ("; + for(unsigned i=0; i<dimension-1; ++i) des += str_max[i] + ","; + des += str_max[dimension-1] + ")"; + } else if( gtype==fibonacci ) { + std::string num; Tools::convert( npoints, num ); + des += "fibonacci grid of " + num + " points on spherical surface"; } return des; } -void GridVessel::resize(){ +void GridVessel::resize() { plumed_massert( nper>0, "Number of datapoints at each grid point has not been set"); - resizeBuffer( getNumberOfBufferPoints()*nper + 1 + 2*getAction()->getNumberOfDerivatives() ); + resizeBuffer( getNumberOfBufferPoints()*nper + 1 + 2*getAction()->getNumberOfDerivatives() ); setDataSize( npoints*nper ); forces.resize( npoints ); if( active.size()!=npoints) active.resize( npoints, true ); } @@ -153,18 +153,18 @@ unsigned GridVessel::getIndex( const std::vector<unsigned>& indices ) const { plumed_dbg_assert( gtype==flat && bounds_set && indices.size()==dimension ); // indices are flattended using a column-major order unsigned index=indices[dimension-1]; - for(unsigned i=dimension-1;i>0;--i){ + for(unsigned i=dimension-1; i>0; --i) { index=index*nbin[i-1]+indices[i-1]; - } + } return index; } -void GridVessel::getIndices( const std::vector<double>& point, std::vector<unsigned>& indices ) const { +void GridVessel::getIndices( const std::vector<double>& point, std::vector<unsigned>& indices ) const { plumed_dbg_assert( gtype==flat && bounds_set && point.size()==dimension && indices.size()==dimension ); - for(unsigned i=0;i<dimension;++i){ - indices[i]=std::floor( (point[i] - min[i])/dx[i] ); - if( pbc[i] ) indices[i]=indices[i]%nbin[i]; - else if( indices[i]>nbin[i] ) plumed_merror("point is outside grid range"); + for(unsigned i=0; i<dimension; ++i) { + indices[i]=std::floor( (point[i] - min[i])/dx[i] ); + if( pbc[i] ) indices[i]=indices[i]%nbin[i]; + else if( indices[i]>nbin[i] ) plumed_merror("point is outside grid range"); } } @@ -175,37 +175,37 @@ unsigned GridVessel::getIndex( const std::vector<double>& point ) const { } void GridVessel::convertIndexToIndices( const unsigned& index, const std::vector<unsigned>& nnbin, std::vector<unsigned>& indices ) const { - plumed_dbg_assert( gtype==flat ); unsigned kk=index; indices[0]=index%nnbin[0]; - for(unsigned i=1;i<dimension-1;++i){ + plumed_dbg_assert( gtype==flat ); unsigned kk=index; indices[0]=index%nnbin[0]; + for(unsigned i=1; i<dimension-1; ++i) { kk=(kk-indices[i-1])/nnbin[i-1]; indices[i]=kk%nnbin[i]; - } - if(dimension>=2){ // I think this is wrong + } + if(dimension>=2) { // I think this is wrong indices[dimension-1]=(kk-indices[dimension-2])/nnbin[dimension-2]; - } + } } void GridVessel::getIndices( const unsigned& index, std::vector<unsigned>& indices ) const { - plumed_dbg_assert( gtype==flat ); convertIndexToIndices( index, nbin, indices ); + plumed_dbg_assert( gtype==flat ); convertIndexToIndices( index, nbin, indices ); } -void GridVessel::getGridPointCoordinates( const unsigned& ipoint , std::vector<double>& x ) const { +void GridVessel::getGridPointCoordinates( const unsigned& ipoint, std::vector<double>& x ) const { plumed_dbg_assert( bounds_set && x.size()==dimension && ipoint<npoints ); - if( gtype==flat ){ - std::vector<unsigned> tindices( dimension ); getIndices( ipoint, tindices ); - for(unsigned i=0;i<dimension;++i) x[i] = min[i] + dx[i]*tindices[i]; - } else if( gtype==fibonacci ){ - x[1] = ((ipoint*fib_offset) - 1) + (fib_offset/2); - double r = sqrt( 1 -x[1]*x[1] ); - double phi = ((ipoint+fib_rnd)%npoints)*fib_increment; - x[0] = r*cos(phi); x[2] = r*sin(phi); - double norm=0; - for(unsigned j=0;j<3;++j) norm+=x[j]*x[j]; - norm = sqrt(norm); - for(unsigned j=0;j<3;++j) x[j] = x[j] / norm; + if( gtype==flat ) { + std::vector<unsigned> tindices( dimension ); getIndices( ipoint, tindices ); + for(unsigned i=0; i<dimension; ++i) x[i] = min[i] + dx[i]*tindices[i]; + } else if( gtype==fibonacci ) { + x[1] = ((ipoint*fib_offset) - 1) + (fib_offset/2); + double r = sqrt( 1 -x[1]*x[1] ); + double phi = ((ipoint+fib_rnd)%npoints)*fib_increment; + x[0] = r*cos(phi); x[2] = r*sin(phi); + double norm=0; + for(unsigned j=0; j<3; ++j) norm+=x[j]*x[j]; + norm = sqrt(norm); + for(unsigned j=0; j<3; ++j) x[j] = x[j] / norm; } else { - plumed_error(); + plumed_error(); } } @@ -215,16 +215,16 @@ void GridVessel::getSplineNeighbors( const unsigned& mybox, std::vector<unsigned std::vector<unsigned> tmp_indices( dimension ); std::vector<unsigned> my_indices( dimension ); getIndices( mybox, my_indices ); - for(unsigned i=0;i<mysneigh.size();++i){ - unsigned tmp=i; - for(unsigned j=0;j<dimension;++j){ - unsigned i0=tmp%2+my_indices[j]; tmp/=2; - if(!pbc[j] && i0==nbin[j]) getAction()->error("Extrapolating function on grid"); - if( pbc[j] && i0==nbin[j]) i0=0; - tmp_indices[j]=i0; - } - mysneigh[i]=getIndex( tmp_indices ); - plumed_massert( active[mysneigh[i]], "inactive grid point required for splines"); + for(unsigned i=0; i<mysneigh.size(); ++i) { + unsigned tmp=i; + for(unsigned j=0; j<dimension; ++j) { + unsigned i0=tmp%2+my_indices[j]; tmp/=2; + if(!pbc[j] && i0==nbin[j]) getAction()->error("Extrapolating function on grid"); + if( pbc[j] && i0==nbin[j]) i0=0; + tmp_indices[j]=i0; + } + mysneigh[i]=getIndex( tmp_indices ); + plumed_massert( active[mysneigh[i]], "inactive grid point required for splines"); } } @@ -233,22 +233,22 @@ double GridVessel::getGridElement( const unsigned& ipoint, const unsigned& jelem return getDataElement( nper*ipoint + jelement ); } -void GridVessel::setGridElement( const unsigned& ipoint, const unsigned& jelement, const double& value ){ +void GridVessel::setGridElement( const unsigned& ipoint, const unsigned& jelement, const double& value ) { plumed_dbg_assert( bounds_set && ipoint<npoints && jelement<nper ); setDataElement( nper*ipoint + jelement, value ); } -void GridVessel::addToGridElement( const unsigned& ipoint, const unsigned& jelement, const double& value ){ +void GridVessel::addToGridElement( const unsigned& ipoint, const unsigned& jelement, const double& value ) { plumed_dbg_assert( bounds_set && ipoint<npoints && jelement<nper ); addDataElement( nper*ipoint + jelement, value ); -} +} void GridVessel::calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const { plumed_dbg_assert( myvals.getNumberOfValues()==(nper+1) ); - for(unsigned i=0;i<nper;++i) buffer[bufstart + nper*current + i] += myvals.get(i+1); + for(unsigned i=0; i<nper; ++i) buffer[bufstart + nper*current + i] += myvals.get(i+1); } -void GridVessel::finish( const std::vector<double>& buffer ){ +void GridVessel::finish( const std::vector<double>& buffer ) { if( wasforced ) getFinalForces( buffer, finalForces ); else AveragingVessel::finish( buffer ); } @@ -257,14 +257,14 @@ double GridVessel::getGridElement( const std::vector<unsigned>& indices, const u return getGridElement( getIndex( indices ), jelement ); } -void GridVessel::setGridElement( const std::vector<unsigned>& indices, const unsigned& jelement, const double& value ){ +void GridVessel::setGridElement( const std::vector<unsigned>& indices, const unsigned& jelement, const double& value ) { setGridElement( getIndex( indices ), jelement, value ); } std::vector<std::string> GridVessel::getMin() const { plumed_dbg_assert( gtype==flat ); return str_min; } - + std::vector<std::string> GridVessel::getMax() const { plumed_dbg_assert( gtype==flat ); return str_max; } @@ -272,9 +272,9 @@ std::vector<std::string> GridVessel::getMax() const { std::vector<unsigned> GridVessel::getNbin() const { plumed_dbg_assert( gtype==flat && bounds_set ); std::vector<unsigned> ngrid( dimension ); - for(unsigned i=0;i<dimension;++i){ - if( !pbc[i] ) ngrid[i]=nbin[i] - 1; - else ngrid[i]=nbin[i]; + for(unsigned i=0; i<dimension; ++i) { + if( !pbc[i] ) ngrid[i]=nbin[i] - 1; + else ngrid[i]=nbin[i]; } return ngrid; } @@ -284,42 +284,42 @@ void GridVessel::getNeighbors( const std::vector<double>& pp, const std::vector< plumed_dbg_assert( gtype==flat && bounds_set && nneigh.size()==dimension ); std::vector<unsigned> indices( dimension ); - for(unsigned i=0;i<dimension;++i) indices[i] = std::floor( (pp[i]-min[i])/dx[i] ); + for(unsigned i=0; i<dimension; ++i) indices[i] = std::floor( (pp[i]-min[i])/dx[i] ); getNeighbors( indices, nneigh, num_neighbors, neighbors ); } -void GridVessel::getNeighbors( const std::vector<unsigned>& indices, const std::vector<unsigned>& nneigh, +void GridVessel::getNeighbors( const std::vector<unsigned>& indices, const std::vector<unsigned>& nneigh, unsigned& num_neighbors, std::vector<unsigned>& neighbors ) const { plumed_dbg_assert( gtype==flat && bounds_set && nneigh.size()==dimension ); unsigned num_neigh=1; std::vector<unsigned> small_bin( dimension ); - for(unsigned i=0;i<dimension;++i){ - small_bin[i]=(2*nneigh[i]+1); - num_neigh *=small_bin[i]; + for(unsigned i=0; i<dimension; ++i) { + small_bin[i]=(2*nneigh[i]+1); + num_neigh *=small_bin[i]; } - if( neighbors.size()!=num_neigh ) neighbors.resize( num_neigh ); + if( neighbors.size()!=num_neigh ) neighbors.resize( num_neigh ); num_neighbors=0; std::vector<unsigned> s_indices(dimension), t_indices(dimension); - for(unsigned index=0;index<num_neigh;++index){ - bool found=true; - convertIndexToIndices( index, small_bin, s_indices ); - for(unsigned i=0;i<dimension;++i){ - int i0=s_indices[i]-nneigh[i]+indices[i]; - if(!pbc[i] && i0<0) found=false; - if(!pbc[i] && i0>=nbin[i]) found=false; - if( pbc[i] && i0<0) i0=nbin[i]-(-i0)%nbin[i]; - if( pbc[i] && i0>=nbin[i]) i0%=nbin[i]; - t_indices[i]=static_cast<unsigned>(i0); - } - if( found ){ - neighbors[num_neighbors]=getIndex( t_indices ); - num_neighbors++; - } + for(unsigned index=0; index<num_neigh; ++index) { + bool found=true; + convertIndexToIndices( index, small_bin, s_indices ); + for(unsigned i=0; i<dimension; ++i) { + int i0=s_indices[i]-nneigh[i]+indices[i]; + if(!pbc[i] && i0<0) found=false; + if(!pbc[i] && i0>=nbin[i]) found=false; + if( pbc[i] && i0<0) i0=nbin[i]-(-i0)%nbin[i]; + if( pbc[i] && i0>=nbin[i]) i0%=nbin[i]; + t_indices[i]=static_cast<unsigned>(i0); + } + if( found ) { + neighbors[num_neighbors]=getIndex( t_indices ); + num_neighbors++; + } } } -void GridVessel::setCubeUnits( const double& units ){ +void GridVessel::setCubeUnits( const double& units ) { plumed_dbg_assert( gtype==flat ); cube_units=units; } @@ -329,17 +329,17 @@ double GridVessel::getCubeUnits() const { std::string GridVessel::getInputString() const { std::string mstring="COORDINATES="+arg_names[0]; - for(unsigned i=1;i<dimension;++i) mstring+="," + arg_names[i]; - if( gtype==flat ){ - mstring += " TYPE=flat PBC="; - if( pbc[0] ) mstring +="T"; - else mstring +="F"; - for(unsigned i=1;i<dimension;++i){ - if( pbc[i] ) mstring +=",T"; - else mstring +=",F"; - } - } else if( gtype==fibonacci ){ - mstring += " TYPE=fibonacci"; + for(unsigned i=1; i<dimension; ++i) mstring+="," + arg_names[i]; + if( gtype==flat ) { + mstring += " TYPE=flat PBC="; + if( pbc[0] ) mstring +="T"; + else mstring +="F"; + for(unsigned i=1; i<dimension; ++i) { + if( pbc[i] ) mstring +=",T"; + else mstring +=",F"; + } + } else if( gtype==fibonacci ) { + mstring += " TYPE=fibonacci"; } return mstring; } @@ -359,56 +359,56 @@ double GridVessel::getValueAndDerivatives( const std::vector<double>& x, const u std::vector<double> xfloor(dimension); getGridPointCoordinates( getIndex(x), xfloor ); // loop over neighbors - for(unsigned int ipoint=0;ipoint<neigh.size();++ipoint){ - double grid=getGridElement(neigh[ipoint], ind*(1+dimension) ); - for(unsigned j=0;j<dimension;++j) dder[j] = getGridElement( neigh[ipoint], ind*(1+dimension) + 1 + j ); - - getIndices( neigh[ipoint], nindices ); - double ff=1.0; - - for(unsigned j=0;j<dimension;++j){ - int x0=1; - if(nindices[j]==indices[j]) x0=0; - double ddx=dx[j]; - X=fabs((x[j]-xfloor[j])/ddx-(double)x0); - X2=X*X; - X3=X2*X; - double yy; - if(fabs(grid)<0.0000001) yy=0.0; - else yy=-dder[j]/grid; - C[j]=(1.0-3.0*X2+2.0*X3) - (x0?-1.0:1.0)*yy*(X-2.0*X2+X3)*ddx; - D[j]=( -6.0*X +6.0*X2) - (x0?-1.0:1.0)*yy*(1.0-4.0*X +3.0*X2)*ddx; - D[j]*=(x0?-1.0:1.0)/ddx; - ff*=C[j]; - } - for(unsigned j=0;j<dimension;++j){ - fd[j]=D[j]; - for(unsigned i=0;i<dimension;++i) if(i!=j) fd[j]*=C[i]; - } - value+=grid*ff; - for(unsigned j=0;j<dimension;++j) der[j]+=grid*fd[j]; + for(unsigned int ipoint=0; ipoint<neigh.size(); ++ipoint) { + double grid=getGridElement(neigh[ipoint], ind*(1+dimension) ); + for(unsigned j=0; j<dimension; ++j) dder[j] = getGridElement( neigh[ipoint], ind*(1+dimension) + 1 + j ); + + getIndices( neigh[ipoint], nindices ); + double ff=1.0; + + for(unsigned j=0; j<dimension; ++j) { + int x0=1; + if(nindices[j]==indices[j]) x0=0; + double ddx=dx[j]; + X=fabs((x[j]-xfloor[j])/ddx-(double)x0); + X2=X*X; + X3=X2*X; + double yy; + if(fabs(grid)<0.0000001) yy=0.0; + else yy=-dder[j]/grid; + C[j]=(1.0-3.0*X2+2.0*X3) - (x0?-1.0:1.0)*yy*(X-2.0*X2+X3)*ddx; + D[j]=( -6.0*X +6.0*X2) - (x0?-1.0:1.0)*yy*(1.0-4.0*X +3.0*X2)*ddx; + D[j]*=(x0?-1.0:1.0)/ddx; + ff*=C[j]; + } + for(unsigned j=0; j<dimension; ++j) { + fd[j]=D[j]; + for(unsigned i=0; i<dimension; ++i) if(i!=j) fd[j]*=C[i]; + } + value+=grid*ff; + for(unsigned j=0; j<dimension; ++j) der[j]+=grid*fd[j]; } return value; } -void GridVessel::activateThesePoints( const std::vector<bool>& to_activate ){ +void GridVessel::activateThesePoints( const std::vector<bool>& to_activate ) { plumed_dbg_assert( to_activate.size()==npoints ); - for(unsigned i=0;i<npoints;++i) active[i]=to_activate[i]; + for(unsigned i=0; i<npoints; ++i) active[i]=to_activate[i]; } -void GridVessel::setForce( const std::vector<double>& inforces ){ +void GridVessel::setForce( const std::vector<double>& inforces ) { plumed_dbg_assert( inforces.size()==npoints ); - wasforced=true; for(unsigned i=0;i<npoints;++i) forces[i]=inforces[i]; + wasforced=true; for(unsigned i=0; i<npoints; ++i) forces[i]=inforces[i]; } bool GridVessel::wasForced() const { return wasforced; } -bool GridVessel::applyForce( std::vector<double>& fforces ){ - plumed_dbg_assert( fforces.size()==finalForces.size() ); +bool GridVessel::applyForce( std::vector<double>& fforces ) { + plumed_dbg_assert( fforces.size()==finalForces.size() ); if( !wasforced ) return false; - for(unsigned i=0;i<finalForces.size();++i) fforces[i]=finalForces[i]; + for(unsigned i=0; i<finalForces.size(); ++i) fforces[i]=finalForces[i]; wasforced=false; return true; } diff --git a/src/gridtools/GridVessel.h b/src/gridtools/GridVessel.h index b513322ff..4cb3c7bee 100644 --- a/src/gridtools/GridVessel.h +++ b/src/gridtools/GridVessel.h @@ -31,154 +31,154 @@ namespace PLMD { namespace gridtools { class GridVessel : public vesselbase::AveragingVessel { -friend class ActionWithInputGrid; -friend class DumpGrid; + friend class ActionWithInputGrid; + friend class DumpGrid; private: /// The way that grid points are constructed - enum {flat,fibonacci} gtype; + enum {flat,fibonacci} gtype; /// Have the minimum and maximum for the grid been set - bool bounds_set; + bool bounds_set; /// The number of points in the grid - unsigned npoints; + unsigned npoints; /// Stuff for fibonacci grids - int fib_rnd; - double fib_offset, fib_increment; + int fib_rnd; + double fib_offset, fib_increment; /// Units for Gaussian Cube file - double cube_units; -/// This flag is used to check if the user has created a valid input - bool foundprint; + double cube_units; +/// This flag is used to check if the user has created a valid input + bool foundprint; /// The minimum and maximum of the grid stored as doubles - std::vector<double> min, max; + std::vector<double> min, max; /// The numerical distance between adjacent grid points - std::vector<unsigned> stride; + std::vector<unsigned> stride; /// The number of bins in each grid direction - std::vector<unsigned> nbin; + std::vector<unsigned> nbin; /// The grid point that was requested last by getGridPointCoordinates - unsigned currentGridPoint; + unsigned currentGridPoint; /// The forces that will be output at the end of the calculation - std::vector<double> finalForces; + std::vector<double> finalForces; protected: /// Is forced - bool wasforced; + bool wasforced; /// Forces acting on grid elements - std::vector<double> forces; + std::vector<double> forces; /// Do we have derivatives - bool noderiv; + bool noderiv; /// The names of the various columns in the grid file - std::vector<std::string> arg_names; -/// The number of pieces of information we are storing for each + std::vector<std::string> arg_names; +/// The number of pieces of information we are storing for each /// point in the grid - unsigned nper; + unsigned nper; /// Is this direction periodic - std::vector<bool> pbc; -/// The minimum and maximum in the grid stored as strings - std::vector<std::string> str_min, str_max; + std::vector<bool> pbc; +/// The minimum and maximum in the grid stored as strings + std::vector<std::string> str_min, str_max; /// The spacing between grid points - std::vector<double> dx; + std::vector<double> dx; /// The dimensionality of the grid - unsigned dimension; + unsigned dimension; /// Which grid points are we actively accumulating - std::vector<bool> active; + std::vector<bool> active; /// Convert a point in space the the correspoinding grid point - unsigned getIndex( const std::vector<double>& p ) const ; + unsigned getIndex( const std::vector<double>& p ) const ; public: /// keywords - static void registerKeywords( Keywords& keys ); + static void registerKeywords( Keywords& keys ); /// Constructor - explicit GridVessel( const vesselbase::VesselOptions& ); -/// Remove the derivatives - void setNoDerivatives(); + explicit GridVessel( const vesselbase::VesselOptions& ); +/// Remove the derivatives + void setNoDerivatives(); /// Get the type of grid we are using - std::string getType() const ; + std::string getType() const ; /// Set the minimum and maximum of the grid - virtual void setBounds( const std::vector<std::string>& smin, const std::vector<std::string>& smax, const std::vector<unsigned>& nbins, const std::vector<double>& spacing ); + virtual void setBounds( const std::vector<std::string>& smin, const std::vector<std::string>& smax, const std::vector<unsigned>& nbins, const std::vector<double>& spacing ); /// Setup the grid if it is a fibonacci grid on the surface of a sphere - void setupFibonacciGrid( const unsigned& np ); + void setupFibonacciGrid( const unsigned& np ); /// Get a description of the grid to output to the log - std::string description(); + std::string description(); /// Convert an index into indices - void convertIndexToIndices( const unsigned& index, const std::vector<unsigned>& nnbin, std::vector<unsigned>& indices ) const ; + void convertIndexToIndices( const unsigned& index, const std::vector<unsigned>& nnbin, std::vector<unsigned>& indices ) const ; /// Flatten the grid and get the grid index for a point - unsigned getIndex( const std::vector<unsigned>& indices ) const ; + unsigned getIndex( const std::vector<unsigned>& indices ) const ; /// Get the indices fof a point - void getIndices( const unsigned& index, std::vector<unsigned>& indices ) const ; + void getIndices( const unsigned& index, std::vector<unsigned>& indices ) const ; /// Get the indices of a particular point - void getIndices( const std::vector<double>& point, std::vector<unsigned>& indices ) const ; + void getIndices( const std::vector<double>& point, std::vector<unsigned>& indices ) const ; /// Operations on one of the elements of grid point i - void setGridElement( const unsigned&, const unsigned&, const double& ); + void setGridElement( const unsigned&, const unsigned&, const double& ); /// Add data to an element of the grid - void addToGridElement( const unsigned& ipoint, const unsigned& jelement, const double& value ); + void addToGridElement( const unsigned& ipoint, const unsigned& jelement, const double& value ); /// Operations on one of the elements of grid point specified by vector - double getGridElement( const std::vector<unsigned>&, const unsigned& ) const ; - void setGridElement( const std::vector<unsigned>&, const unsigned&, const double& ); + double getGridElement( const std::vector<unsigned>&, const unsigned& ) const ; + void setGridElement( const std::vector<unsigned>&, const unsigned&, const double& ); /// Set the size of the buffer equal to nper*npoints - virtual void resize(); + virtual void resize(); /// Get the number of points in the grid - unsigned getNumberOfPoints() const; + unsigned getNumberOfPoints() const; /// Get the coordinates for a point in the grid - void getGridPointCoordinates( const unsigned& , std::vector<double>& ) const ; + void getGridPointCoordinates( const unsigned&, std::vector<double>& ) const ; /// Get the dimensionality of the function - unsigned getDimension() const ; + unsigned getDimension() const ; /// Get the number of components in the vector stored on each grid point - virtual unsigned getNumberOfComponents() const ; + virtual unsigned getNumberOfComponents() const ; /// Is the grid periodic in the ith direction - bool isPeriodic( const unsigned& i ) const ; + bool isPeriodic( const unsigned& i ) const ; /// Get the number of quantities we have stored at each grid point - unsigned getNumberOfQuantities() const ; + unsigned getNumberOfQuantities() const ; /// Get the number of grid points for each dimension - std::vector<unsigned> getNbin() const ; + std::vector<unsigned> getNbin() const ; /// Get the name of the ith component - std::string getComponentName( const unsigned& i ) const ; + std::string getComponentName( const unsigned& i ) const ; /// Get the vector containing the minimum value of the grid in each dimension - std::vector<std::string> getMin() const ; + std::vector<std::string> getMin() const ; /// Get the vector containing the maximum value of the grid in each dimension - std::vector<std::string> getMax() const ; + std::vector<std::string> getMax() const ; /// Get the number of points needed in the buffer - virtual unsigned getNumberOfBufferPoints() const ; + virtual unsigned getNumberOfBufferPoints() const ; /// Get the stride (the distance between the grid points of an index) - const std::vector<unsigned>& getStride() const ; + const std::vector<unsigned>& getStride() const ; /// Return the volume of one of the grid cells - double getCellVolume() const ; -/// Get the value of the ith grid element - virtual double getGridElement( const unsigned&, const unsigned& ) const ; + double getCellVolume() const ; +/// Get the value of the ith grid element + virtual double getGridElement( const unsigned&, const unsigned& ) const ; /// Get the set of points neighouring a particular location in space - void getNeighbors( const std::vector<double>& pp, const std::vector<unsigned>& nneigh, - unsigned& num_neighbours, std::vector<unsigned>& neighbors ) const ; + void getNeighbors( const std::vector<double>& pp, const std::vector<unsigned>& nneigh, + unsigned& num_neighbours, std::vector<unsigned>& neighbors ) const ; /// Get the neighbors for a set of indices of a point - void getNeighbors( const std::vector<unsigned>& indices, const std::vector<unsigned>& nneigh, - unsigned& num_neighbors, std::vector<unsigned>& neighbors ) const ; + void getNeighbors( const std::vector<unsigned>& indices, const std::vector<unsigned>& nneigh, + unsigned& num_neighbors, std::vector<unsigned>& neighbors ) const ; /// Get the points neighboring a particular spline point - void getSplineNeighbors( const unsigned& mybox, std::vector<unsigned>& mysneigh ) const ; + void getSplineNeighbors( const unsigned& mybox, std::vector<unsigned>& mysneigh ) const ; /// Get the spacing between grid points - const std::vector<double>& getGridSpacing() const ; + const std::vector<double>& getGridSpacing() const ; /// Get the extent of the grid in one of the axis - double getGridExtent( const unsigned& i ) const ; + double getGridExtent( const unsigned& i ) const ; /// Copy data from the action into the grid - virtual void calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const ; + virtual void calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const ; /// Finish the calculation - virtual void finish( const std::vector<double>& buffer ); + virtual void finish( const std::vector<double>& buffer ); /// This ensures that Gaussian cube fies are in correct units - void setCubeUnits( const double& units ); + void setCubeUnits( const double& units ); /// This ensures that Gaussian cube files are in correct units - double getCubeUnits() const ; + double getCubeUnits() const ; /// Return a string containing the input to the grid so we can clone it - std::string getInputString() const ; + std::string getInputString() const ; /// Does this have derivatives - bool noDerivatives() const ; + bool noDerivatives() const ; /// Get the value and derivatives at a particular location using spline interpolation - double getValueAndDerivatives( const std::vector<double>& x, const unsigned& ind, std::vector<double>& der ) const ; + double getValueAndDerivatives( const std::vector<double>& x, const unsigned& ind, std::vector<double>& der ) const ; /// Deactivate all the grid points - void activateThesePoints( const std::vector<bool>& to_activate ); + void activateThesePoints( const std::vector<bool>& to_activate ); /// Is this point active - bool inactive( const unsigned& ip ) const ; + bool inactive( const unsigned& ip ) const ; /// This retrieves the final force - virtual void getFinalForces( const std::vector<double>& buffer, std::vector<double>& finalForces ){ plumed_error(); } + virtual void getFinalForces( const std::vector<double>& buffer, std::vector<double>& finalForces ) { plumed_error(); } /// Apply the forces - void setForce( const std::vector<double>& inforces ); + void setForce( const std::vector<double>& inforces ); /// Was a force added to the grid - bool wasForced() const ; + bool wasForced() const ; /// And retrieve the forces - bool applyForce( std::vector<double>& fforces ); + bool applyForce( std::vector<double>& fforces ); }; inline @@ -200,11 +200,11 @@ const std::vector<double>& GridVessel::getGridSpacing() const { inline double GridVessel::getCellVolume() const { - if( gtype==flat ){ - double myvol=1.0; for(unsigned i=0;i<dimension;++i) myvol *= dx[i]; - return myvol; + if( gtype==flat ) { + double myvol=1.0; for(unsigned i=0; i<dimension; ++i) myvol *= dx[i]; + return myvol; } else { - return 4*pi / static_cast<double>( getNumberOfPoints() ); + return 4*pi / static_cast<double>( getNumberOfPoints() ); } } diff --git a/src/gridtools/HistogramOnGrid.cpp b/src/gridtools/HistogramOnGrid.cpp index 6fac76cd5..43fe891c2 100644 --- a/src/gridtools/HistogramOnGrid.cpp +++ b/src/gridtools/HistogramOnGrid.cpp @@ -25,7 +25,7 @@ namespace PLMD { namespace gridtools { -void HistogramOnGrid::registerKeywords( Keywords& keys ){ +void HistogramOnGrid::registerKeywords( Keywords& keys ) { GridVessel::registerKeywords( keys ); keys.add("compulsory","KERNEL","the type of kernel to use"); keys.add("compulsory","BANDWIDTH","the bandwidths"); @@ -33,23 +33,23 @@ void HistogramOnGrid::registerKeywords( Keywords& keys ){ } HistogramOnGrid::HistogramOnGrid( const vesselbase::VesselOptions& da ): -GridVessel(da), -neigh_tot(0), -addOneKernelAtATime(false), -bandwidths(dimension), -discrete(false) + GridVessel(da), + neigh_tot(0), + addOneKernelAtATime(false), + bandwidths(dimension), + discrete(false) { - if( getType()=="flat" ){ - parse("KERNEL",kerneltype); - if( kerneltype=="discrete" || kerneltype=="DISCRETE" ){ - discrete=true; setNoDerivatives(); - } else { - parseVector("BANDWIDTH",bandwidths); - } + if( getType()=="flat" ) { + parse("KERNEL",kerneltype); + if( kerneltype=="discrete" || kerneltype=="DISCRETE" ) { + discrete=true; setNoDerivatives(); + } else { + parseVector("BANDWIDTH",bandwidths); + } } else { - parse("CONCENTRATION",von_misses_concentration); - von_misses_norm = von_misses_concentration / ( 4*pi*sinh( von_misses_concentration ) ); - } + parse("CONCENTRATION",von_misses_concentration); + von_misses_norm = von_misses_concentration / ( 4*pi*sinh( von_misses_concentration ) ); + } } bool HistogramOnGrid::noDiscreteKernels() const { @@ -57,151 +57,151 @@ bool HistogramOnGrid::noDiscreteKernels() const { } void HistogramOnGrid::setBounds( const std::vector<std::string>& smin, const std::vector<std::string>& smax, - const std::vector<unsigned>& nbins, const std::vector<double>& spacing ){ + const std::vector<unsigned>& nbins, const std::vector<double>& spacing ) { GridVessel::setBounds( smin, smax, nbins, spacing ); - if( !discrete ){ - std::vector<double> point(dimension,0); - KernelFunctions kernel( point, bandwidths, kerneltype, false, 1.0, true ); neigh_tot=1; - nneigh=kernel.getSupport( dx ); std::vector<double> support( kernel.getContinuousSupport() ); - for(unsigned i=0;i<dimension;++i){ - if( pbc[i] && 2*support[i]>getGridExtent(i) ) error("bandwidth is too large for periodic grid"); - neigh_tot *= (2*nneigh[i]+1); - } - } + if( !discrete ) { + std::vector<double> point(dimension,0); + KernelFunctions kernel( point, bandwidths, kerneltype, false, 1.0, true ); neigh_tot=1; + nneigh=kernel.getSupport( dx ); std::vector<double> support( kernel.getContinuousSupport() ); + for(unsigned i=0; i<dimension; ++i) { + if( pbc[i] && 2*support[i]>getGridExtent(i) ) error("bandwidth is too large for periodic grid"); + neigh_tot *= (2*nneigh[i]+1); + } + } } KernelFunctions* HistogramOnGrid::getKernelAndNeighbors( std::vector<double>& point, unsigned& num_neigh, std::vector<unsigned>& neighbors ) const { - if( discrete ){ - plumed_assert( getType()=="flat" ); - num_neigh=1; for(unsigned i=0;i<dimension;++i) point[i] += 0.5*dx[i]; - neighbors[0] = getIndex( point ); return NULL; - } else if( getType()=="flat" ){ - KernelFunctions* kernel = new KernelFunctions( point, bandwidths, kerneltype, false, 1.0, true ); - getNeighbors( kernel->getCenter(), nneigh, num_neigh, neighbors ); - return kernel; + if( discrete ) { + plumed_assert( getType()=="flat" ); + num_neigh=1; for(unsigned i=0; i<dimension; ++i) point[i] += 0.5*dx[i]; + neighbors[0] = getIndex( point ); return NULL; + } else if( getType()=="flat" ) { + KernelFunctions* kernel = new KernelFunctions( point, bandwidths, kerneltype, false, 1.0, true ); + getNeighbors( kernel->getCenter(), nneigh, num_neigh, neighbors ); + return kernel; } else { - num_neigh = getNumberOfPoints(); - if( neighbors.size()!=getNumberOfPoints() ) neighbors.resize( getNumberOfPoints() ); - for(unsigned i=0;i<getNumberOfPoints();++i) neighbors[i]=i; + num_neigh = getNumberOfPoints(); + if( neighbors.size()!=getNumberOfPoints() ) neighbors.resize( getNumberOfPoints() ); + for(unsigned i=0; i<getNumberOfPoints(); ++i) neighbors[i]=i; } return NULL; } std::vector<Value*> HistogramOnGrid::getVectorOfValues() const { std::vector<Value*> vv; - for(unsigned i=0;i<dimension;++i){ - vv.push_back(new Value()); - if( pbc[i] ) vv[i]->setDomain( str_min[i], str_max[i] ); - else vv[i]->setNotPeriodic(); + for(unsigned i=0; i<dimension; ++i) { + vv.push_back(new Value()); + if( pbc[i] ) vv[i]->setDomain( str_min[i], str_max[i] ); + else vv[i]->setNotPeriodic(); } return vv; } void HistogramOnGrid::calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const { - if( addOneKernelAtATime ){ - plumed_dbg_assert( myvals.getNumberOfValues()==2 && !wasforced ); - std::vector<double> der( dimension ); - for(unsigned i=0;i<dimension;++i) der[i]=myvals.getDerivative( 1, i ); - accumulate( getAction()->getPositionInCurrentTaskList(current), myvals.get(0), myvals.get(1), der, buffer ); + if( addOneKernelAtATime ) { + plumed_dbg_assert( myvals.getNumberOfValues()==2 && !wasforced ); + std::vector<double> der( dimension ); + for(unsigned i=0; i<dimension; ++i) der[i]=myvals.getDerivative( 1, i ); + accumulate( getAction()->getPositionInCurrentTaskList(current), myvals.get(0), myvals.get(1), der, buffer ); } else { - plumed_dbg_assert( myvals.getNumberOfValues()==dimension+2 ); - std::vector<double> point( dimension ); double weight=myvals.get(0)*myvals.get( 1+dimension ); - for(unsigned i=0;i<dimension;++i) point[i]=myvals.get( 1+i ); - - // Get the kernel - unsigned num_neigh; std::vector<unsigned> neighbors; - std::vector<double> der( dimension ); - KernelFunctions* kernel=getKernelAndNeighbors( point, num_neigh, neighbors ); - - if( !kernel && getType()=="flat" ){ - plumed_dbg_assert( num_neigh==1 ); der.resize(0); - accumulate( neighbors[0], weight, 1.0, der, buffer ); - } else { - double totwforce=0.0; - std::vector<double> intforce( 2*dimension, 0.0 ); - std::vector<Value*> vv( getVectorOfValues() ); - - double newval; std::vector<double> xx( dimension ); - for(unsigned i=0;i<num_neigh;++i){ - unsigned ineigh=neighbors[i]; - if( inactive( ineigh ) ) continue ; - getGridPointCoordinates( ineigh, xx ); - if( kernel ){ - for(unsigned j=0;j<dimension;++j) vv[j]->set(xx[j]); - newval = kernel->evaluate( vv, der, true ); - } else { - // Evalulate dot product - double dot=0; for(unsigned j=0;j<dimension;++j){ dot+=xx[j]*point[j]; der[j]=xx[j]; } - // Von misses distribution for concentration parameter - newval = von_misses_norm*exp( von_misses_concentration*dot ); - // And final derivatives - for(unsigned j=0;j<dimension;++j) der[j] *= von_misses_concentration*newval; - } - accumulate( ineigh, weight, newval, der, buffer ); - if( wasForced() ){ - accumulateForce( ineigh, weight, der, intforce ); - totwforce += myvals.get( 1+dimension )*newval*forces[ineigh]; - } - } - if( wasForced() ){ - // Minus sign for kernel here as we are taking derivative with respect to position of center of - // kernel NOT derivative wrt to grid point - double pref = 1; if( kernel ) pref = -1; - unsigned nder = getAction()->getNumberOfDerivatives(); - unsigned gridbuf = getNumberOfBufferPoints()*getNumberOfQuantities(); - for(unsigned j=0;j<dimension;++j){ - for(unsigned k=0;k<myvals.getNumberActive();++k){ - unsigned kder=myvals.getActiveIndex(k); - buffer[ bufstart + gridbuf + kder ] += pref*intforce[j]*myvals.getDerivative( j+1, kder ); - } - } - // Accumulate the sum of all the weights - buffer[ bufstart + gridbuf + nder ] += myvals.get(0); - // Add the derivatives of the weights into the force -- this is separate loop as weights of all parts are considered together - for(unsigned k=0;k<myvals.getNumberActive();++k){ - unsigned kder=myvals.getActiveIndex(k); - buffer[ bufstart + gridbuf + kder ] += totwforce*myvals.getDerivative( 0, kder ); - buffer[ bufstart + gridbuf + nder + 1 + kder ] += myvals.getDerivative( 0, kder ); - } - } - delete kernel; for(unsigned i=0;i<dimension;++i) delete vv[i]; - } + plumed_dbg_assert( myvals.getNumberOfValues()==dimension+2 ); + std::vector<double> point( dimension ); double weight=myvals.get(0)*myvals.get( 1+dimension ); + for(unsigned i=0; i<dimension; ++i) point[i]=myvals.get( 1+i ); + + // Get the kernel + unsigned num_neigh; std::vector<unsigned> neighbors; + std::vector<double> der( dimension ); + KernelFunctions* kernel=getKernelAndNeighbors( point, num_neigh, neighbors ); + + if( !kernel && getType()=="flat" ) { + plumed_dbg_assert( num_neigh==1 ); der.resize(0); + accumulate( neighbors[0], weight, 1.0, der, buffer ); + } else { + double totwforce=0.0; + std::vector<double> intforce( 2*dimension, 0.0 ); + std::vector<Value*> vv( getVectorOfValues() ); + + double newval; std::vector<double> xx( dimension ); + for(unsigned i=0; i<num_neigh; ++i) { + unsigned ineigh=neighbors[i]; + if( inactive( ineigh ) ) continue ; + getGridPointCoordinates( ineigh, xx ); + if( kernel ) { + for(unsigned j=0; j<dimension; ++j) vv[j]->set(xx[j]); + newval = kernel->evaluate( vv, der, true ); + } else { + // Evalulate dot product + double dot=0; for(unsigned j=0; j<dimension; ++j) { dot+=xx[j]*point[j]; der[j]=xx[j]; } + // Von misses distribution for concentration parameter + newval = von_misses_norm*exp( von_misses_concentration*dot ); + // And final derivatives + for(unsigned j=0; j<dimension; ++j) der[j] *= von_misses_concentration*newval; + } + accumulate( ineigh, weight, newval, der, buffer ); + if( wasForced() ) { + accumulateForce( ineigh, weight, der, intforce ); + totwforce += myvals.get( 1+dimension )*newval*forces[ineigh]; + } + } + if( wasForced() ) { + // Minus sign for kernel here as we are taking derivative with respect to position of center of + // kernel NOT derivative wrt to grid point + double pref = 1; if( kernel ) pref = -1; + unsigned nder = getAction()->getNumberOfDerivatives(); + unsigned gridbuf = getNumberOfBufferPoints()*getNumberOfQuantities(); + for(unsigned j=0; j<dimension; ++j) { + for(unsigned k=0; k<myvals.getNumberActive(); ++k) { + unsigned kder=myvals.getActiveIndex(k); + buffer[ bufstart + gridbuf + kder ] += pref*intforce[j]*myvals.getDerivative( j+1, kder ); + } + } + // Accumulate the sum of all the weights + buffer[ bufstart + gridbuf + nder ] += myvals.get(0); + // Add the derivatives of the weights into the force -- this is separate loop as weights of all parts are considered together + for(unsigned k=0; k<myvals.getNumberActive(); ++k) { + unsigned kder=myvals.getActiveIndex(k); + buffer[ bufstart + gridbuf + kder ] += totwforce*myvals.getDerivative( 0, kder ); + buffer[ bufstart + gridbuf + nder + 1 + kder ] += myvals.getDerivative( 0, kder ); + } + } + delete kernel; for(unsigned i=0; i<dimension; ++i) delete vv[i]; + } } } void HistogramOnGrid::accumulate( const unsigned& ipoint, const double& weight, const double& dens, const std::vector<double>& der, std::vector<double>& buffer ) const { - buffer[bufstart+nper*ipoint] += weight*dens; - if( der.size()>0 ) for(unsigned j=0;j<dimension;++j) buffer[bufstart+nper*ipoint + 1 + j] += weight*der[j]; + buffer[bufstart+nper*ipoint] += weight*dens; + if( der.size()>0 ) for(unsigned j=0; j<dimension; ++j) buffer[bufstart+nper*ipoint + 1 + j] += weight*der[j]; } void HistogramOnGrid::accumulateForce( const unsigned& ipoint, const double& weight, const std::vector<double>& der, std::vector<double>& intforce ) const { - for(unsigned j=0;j<der.size();++j) intforce[j] += forces[ipoint]*weight*der[j]; + for(unsigned j=0; j<der.size(); ++j) intforce[j] += forces[ipoint]*weight*der[j]; } -void HistogramOnGrid::getFinalForces( const std::vector<double>& buffer, std::vector<double>& finalForces ){ +void HistogramOnGrid::getFinalForces( const std::vector<double>& buffer, std::vector<double>& finalForces ) { if( finalForces.size()!=getAction()->getNumberOfDerivatives() ) finalForces.resize( getAction()->getNumberOfDerivatives() ); // And the final force - unsigned nder = getAction()->getNumberOfDerivatives(); + unsigned nder = getAction()->getNumberOfDerivatives(); // Derivatives due to normalization unsigned gridbuf = getNumberOfBufferPoints()*getNumberOfQuantities(); - for(unsigned i=0;i<finalForces.size();++i) finalForces[i] = buffer[ bufstart + gridbuf + i ]; + for(unsigned i=0; i<finalForces.size(); ++i) finalForces[i] = buffer[ bufstart + gridbuf + i ]; // Derivatives due to normalization - if( !noAverage() ){ - unsigned wderstart = bufstart + gridbuf + nder; double pref=0; - for(unsigned ipoint=0;ipoint<getNumberOfPoints();++ipoint){ - pref += forces[ipoint]*buffer[ bufstart + ipoint*nper ] / buffer[wderstart]; - } - for(unsigned j=0;j<finalForces.size();++j) finalForces[j] -= pref*buffer[ wderstart + 1 + j ]; + if( !noAverage() ) { + unsigned wderstart = bufstart + gridbuf + nder; double pref=0; + for(unsigned ipoint=0; ipoint<getNumberOfPoints(); ++ipoint) { + pref += forces[ipoint]*buffer[ bufstart + ipoint*nper ] / buffer[wderstart]; + } + for(unsigned j=0; j<finalForces.size(); ++j) finalForces[j] -= pref*buffer[ wderstart + 1 + j ]; } } -void HistogramOnGrid::finish( const std::vector<double>& buffer ){ - if( addOneKernelAtATime ){ - for(unsigned i=0;i<getAction()->getCurrentNumberOfActiveTasks();++i){ - for(unsigned j=0;j<nper;++j) addDataElement( nper*getAction()->getActiveTask(i)+j, buffer[bufstart+i*nper+j] ); - } +void HistogramOnGrid::finish( const std::vector<double>& buffer ) { + if( addOneKernelAtATime ) { + for(unsigned i=0; i<getAction()->getCurrentNumberOfActiveTasks(); ++i) { + for(unsigned j=0; j<nper; ++j) addDataElement( nper*getAction()->getActiveTask(i)+j, buffer[bufstart+i*nper+j] ); + } } else { - GridVessel::finish( buffer ); + GridVessel::finish( buffer ); } } diff --git a/src/gridtools/HistogramOnGrid.h b/src/gridtools/HistogramOnGrid.h index 5171a9f6c..2eb9a253d 100644 --- a/src/gridtools/HistogramOnGrid.h +++ b/src/gridtools/HistogramOnGrid.h @@ -53,7 +53,7 @@ public: unsigned getNumberOfBufferPoints() const ; KernelFunctions* getKernelAndNeighbors( std::vector<double>& point, unsigned& num_neigh, std::vector<unsigned>& neighbors ) const; std::vector<Value*> getVectorOfValues() const ; - void addOneKernelEachTimeOnly(){ addOneKernelAtATime=true; } + void addOneKernelEachTimeOnly() { addOneKernelAtATime=true; } virtual void getFinalForces( const std::vector<double>& buffer, std::vector<double>& finalForces ); bool noDiscreteKernels() const ; }; diff --git a/src/gridtools/IntegrateGrid.cpp b/src/gridtools/IntegrateGrid.cpp index 02f59826a..fc966a46d 100644 --- a/src/gridtools/IntegrateGrid.cpp +++ b/src/gridtools/IntegrateGrid.cpp @@ -43,13 +43,13 @@ public: PLUMED_REGISTER_ACTION(IntegrateGrid,"INTEGRATE_GRID") -void IntegrateGrid::registerKeywords( Keywords& keys ){ +void IntegrateGrid::registerKeywords( Keywords& keys ) { ActionWithIntegral::registerKeywords( keys ); } IntegrateGrid::IntegrateGrid(const ActionOptions&ao): -Action(ao), -ActionWithIntegral(ao) + Action(ao), + ActionWithIntegral(ao) { } diff --git a/src/gridtools/InterpolateGrid.cpp b/src/gridtools/InterpolateGrid.cpp index f35f10de8..e8f97c0d4 100644 --- a/src/gridtools/InterpolateGrid.cpp +++ b/src/gridtools/InterpolateGrid.cpp @@ -28,20 +28,20 @@ /* Interpolate a smooth function stored on a grid onto a grid with a smaller grid spacing. -This action takes a function evaluated on a grid as input and can be used to interpolate the values of that +This action takes a function evaluated on a grid as input and can be used to interpolate the values of that function on to a finer grained grid. The interpolation within this algorithm is done using splines. \par Examples -The input below can be used to postprocess a trajectory. It calculates a \ref HISTOGRAM as a function the +The input below can be used to postprocess a trajectory. It calculates a \ref HISTOGRAM as a function the distance between atoms 1 and 2 using kernel density estimation. During the calculation the values of the kernels -are evaluated at 100 points on a uniform grid between 0.0 and 3.0. Prior to outputting this function at the end of the -simulation this function is interpolated onto a finer grid of 200 points between 0.0 and 3.0. +are evaluated at 100 points on a uniform grid between 0.0 and 3.0. Prior to outputting this function at the end of the +simulation this function is interpolated onto a finer grid of 200 points between 0.0 and 3.0. \verbatim x: DISTANCE ATOMS=1,2 -hA1: HISTOGRAM ARG=x GRID_MIN=0.0 GRID_MAX=3.0 GRID_BIN=100 BANDWIDTH=0.1 -ii: INTERPOLATE_GRID GRID=hA1 GRID_BIN=200 +hA1: HISTOGRAM ARG=x GRID_MIN=0.0 GRID_MAX=3.0 GRID_BIN=100 BANDWIDTH=0.1 +ii: INTERPOLATE_GRID GRID=hA1 GRID_BIN=200 DUMPGRID GRID=ii FILE=histo.dat \endverbatim @@ -57,42 +57,42 @@ public: explicit InterpolateGrid(const ActionOptions&ao); unsigned getNumberOfQuantities() const ; void compute( const unsigned& current, MultiValue& myvals ) const ; - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } }; PLUMED_REGISTER_ACTION(InterpolateGrid,"INTERPOLATE_GRID") -void InterpolateGrid::registerKeywords( Keywords& keys ){ +void InterpolateGrid::registerKeywords( Keywords& keys ) { ActionWithInputGrid::registerKeywords( keys ); keys.add("optional","GRID_BIN","the number of bins for the grid"); keys.add("optional","GRID_SPACING","the approximate grid spacing (to be used as an alternative or together with GRID_BIN)"); - keys.remove("KERNEL"); keys.remove("BANDWIDTH"); + keys.remove("KERNEL"); keys.remove("BANDWIDTH"); } InterpolateGrid::InterpolateGrid(const ActionOptions&ao): -Action(ao), -ActionWithInputGrid(ao) + Action(ao), + ActionWithInputGrid(ao) { plumed_assert( ingrid->getNumberOfComponents()==1 ); - if( ingrid->noDerivatives() ) error("cannot interpolate a grid that does not have derivatives"); + if( ingrid->noDerivatives() ) error("cannot interpolate a grid that does not have derivatives"); // Create the input from the old string createGrid( "grid", "COMPONENTS=" + getLabel() + " " + ingrid->getInputString() ); - std::vector<unsigned> nbin; parseVector("GRID_BIN",nbin); + std::vector<unsigned> nbin; parseVector("GRID_BIN",nbin); std::vector<double> gspacing; parseVector("GRID_SPACING",gspacing); - if( nbin.size()!=ingrid->getDimension() && gspacing.size()!=ingrid->getDimension() ){ - error("GRID_BIN or GRID_SPACING must be set"); - } + if( nbin.size()!=ingrid->getDimension() && gspacing.size()!=ingrid->getDimension() ) { + error("GRID_BIN or GRID_SPACING must be set"); + } // Need this for creation of tasks - mygrid->setBounds( ingrid->getMin(), ingrid->getMax(), nbin, gspacing ); + mygrid->setBounds( ingrid->getMin(), ingrid->getMax(), nbin, gspacing ); setAveragingAction( mygrid, true ); // Now create task list - for(unsigned i=0;i<mygrid->getNumberOfPoints();++i) addTaskToList(i); + for(unsigned i=0; i<mygrid->getNumberOfPoints(); ++i) addTaskToList(i); // And activate all tasks - deactivateAllTasks(); - for(unsigned i=0;i<mygrid->getNumberOfPoints();++i) taskFlags[i]=1; + deactivateAllTasks(); + for(unsigned i=0; i<mygrid->getNumberOfPoints(); ++i) taskFlags[i]=1; lockContributors(); } @@ -103,8 +103,8 @@ unsigned InterpolateGrid::getNumberOfQuantities() const { void InterpolateGrid::compute( const unsigned& current, MultiValue& myvals ) const { std::vector<double> pos( mygrid->getDimension() ); mygrid->getGridPointCoordinates( current, pos ); std::vector<double> der( mygrid->getDimension() ); double val = getFunctionValueAndDerivatives( pos, der ); - myvals.setValue( 0, 1.0 ); myvals.setValue(1, val ); - for(unsigned i=0;i<mygrid->getDimension();++i) myvals.setValue( 2+i, der[i] ); + myvals.setValue( 0, 1.0 ); myvals.setValue(1, val ); + for(unsigned i=0; i<mygrid->getDimension(); ++i) myvals.setValue( 2+i, der[i] ); } } diff --git a/src/main/main.cpp b/src/main/main.cpp index 797ce8039..4e3d6376c 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -32,10 +32,10 @@ using namespace std; This main uses only the interface published in Plumed.h. The object file generated from this .cpp is the only part of the plumed library that should - not be linked with external MD codes, so as + not be linked with external MD codes, so as to avoid linker error. */ -int main(int argc,char**argv){ +int main(int argc,char**argv) { #ifdef __PLUMED_HAS_MPI bool nompi=false; if(argc>1 && !strcmp(argv[1],"--no-mpi")) nompi=true; @@ -48,7 +48,7 @@ int main(int argc,char**argv){ p->cmd("CLTool setArgc",&argc); p->cmd("CLTool setArgv",argv); #ifdef __PLUMED_HAS_MPI - if(!nompi){ + if(!nompi) { MPI_Comm comm; MPI_Comm_dup(MPI_COMM_WORLD,&comm); p->cmd("CLTool setMPIComm",&comm); diff --git a/src/manyrestraints/LWalls.cpp b/src/manyrestraints/LWalls.cpp index 4075bacd8..7c0ad569e 100644 --- a/src/manyrestraints/LWalls.cpp +++ b/src/manyrestraints/LWalls.cpp @@ -25,7 +25,7 @@ namespace PLMD { namespace manyrestraints { -//+PLUMEDOC MCOLVARB LWALLS +//+PLUMEDOC MCOLVARB LWALLS /* Add \ref LOWER_WALLS restraints on all the multicolvar values @@ -36,20 +36,20 @@ keyword and places a restraint on each quantity, \f$x\f$, with the following fun k((x-a+o)/s)^e \f$ -\f$k\f$ (KAPPA) is an energy constant in internal unit of the code, \f$s\f$ (EPS) a rescaling factor and +\f$k\f$ (KAPPA) is an energy constant in internal unit of the code, \f$s\f$ (EPS) a rescaling factor and \f$e\f$ (EXP) the exponent determining the power law. By default: EXP = 2, EPS = 1.0, OFF = 0. \par Examples The following set of commands can be used to stop any of the 800 atoms in group A from moving more than 2.46425 nm -in the z direction from atom 34137. This is done by adding a lower wall on the z-distance between all the atoms in -group A and the position of 34137. +in the z direction from atom 34137. This is done by adding a lower wall on the z-distance between all the atoms in +group A and the position of 34137. \verbatim l: ZDISTANCES GROUPA=1-800 GROUPB=34137 NOPBC LWALLS DATA=l AT=2.46465 KAPPA=150.0 EXP=2 EPS=1 OFFSET=0 LABEL=lwall \endverbatim - + */ //+ENDPLUMEDOC @@ -70,7 +70,7 @@ public: PLUMED_REGISTER_ACTION(LWalls,"LWALLS") -void LWalls::registerKeywords( Keywords& keys ){ +void LWalls::registerKeywords( Keywords& keys ) { ManyRestraintsBase::registerKeywords( keys ); keys.add("compulsory","AT","the radius of the sphere"); keys.add("compulsory","KAPPA","the force constant for the wall. The k_i in the expression for a wall."); @@ -80,8 +80,8 @@ void LWalls::registerKeywords( Keywords& keys ){ } LWalls::LWalls(const ActionOptions& ao): -Action(ao), -ManyRestraintsBase(ao) + Action(ao), + ManyRestraintsBase(ao) { parse("AT",at); parse("OFFSET",offset); @@ -91,13 +91,13 @@ ManyRestraintsBase(ao) checkRead(); } -double LWalls::calcPotential( const double& val, double& df ) const { +double LWalls::calcPotential( const double& val, double& df ) const { double uscale = (val - at + offset)/eps; - if( uscale < 0. ){ - double power = pow( uscale, exp ); - df = ( kappa / eps ) * exp * power / uscale; + if( uscale < 0. ) { + double power = pow( uscale, exp ); + df = ( kappa / eps ) * exp * power / uscale; - return kappa*power; + return kappa*power; } return 0.0; diff --git a/src/manyrestraints/ManyRestraintsBase.cpp b/src/manyrestraints/ManyRestraintsBase.cpp index 60dd82b2e..d13d51cfa 100644 --- a/src/manyrestraints/ManyRestraintsBase.cpp +++ b/src/manyrestraints/ManyRestraintsBase.cpp @@ -25,7 +25,7 @@ namespace PLMD { namespace manyrestraints { -void ManyRestraintsBase::registerKeywords( Keywords& keys ){ +void ManyRestraintsBase::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionWithValue::registerKeywords( keys ); ActionWithVessel::registerKeywords( keys ); @@ -37,11 +37,11 @@ void ManyRestraintsBase::registerKeywords( Keywords& keys ){ } ManyRestraintsBase::ManyRestraintsBase(const ActionOptions& ao): -Action(ao), -ActionWithValue(ao), -ActionPilot(ao), -ActionWithVessel(ao), -ActionWithInputVessel(ao) + Action(ao), + ActionWithValue(ao), + ActionPilot(ao), + ActionWithVessel(ao), + ActionWithInputVessel(ao) { // Read in the vessel we are action on readArgument("bridge"); @@ -49,44 +49,44 @@ ActionWithInputVessel(ao) plumed_assert( getDependencies().size()==1 && aves ); log.printf(" adding restraints on variables calculated by %s action with label %s\n", - aves->getName().c_str(),aves->getLabel().c_str()); + aves->getName().c_str(),aves->getLabel().c_str()); // Add a task list in order to avoid problems - for(unsigned i=0;i<aves->getFullNumberOfTasks();++i) addTaskToList( aves->getTaskCode(i) ); + for(unsigned i=0; i<aves->getFullNumberOfTasks(); ++i) addTaskToList( aves->getTaskCode(i) ); // And turn on the derivatives (note problems here because of ActionWithValue) turnOnDerivatives(); needsDerivatives(); // Now create the vessel std::string fake_input="LABEL=bias"; - addVessel( "SUM", fake_input, 0 ); + addVessel( "SUM", fake_input, 0 ); readVesselKeywords(); } -void ManyRestraintsBase::doJobsRequiredBeforeTaskList(){ +void ManyRestraintsBase::doJobsRequiredBeforeTaskList() { ActionWithVessel::doJobsRequiredBeforeTaskList(); ActionWithValue::clearDerivatives(); } void ManyRestraintsBase::transformBridgedDerivatives( const unsigned& current, MultiValue& invals, MultiValue& outvals ) const { outvals.setValue( 0, invals.get(0) ); - + // Get the potential double dval=0, val=calcPotential( invals.get(1), dval ); outvals.setValue( 1, val ); - for(unsigned i=0;i<invals.getNumberActive();++i){ - unsigned jder=invals.getActiveIndex(i); - outvals.addDerivative( 1, jder, dval*invals.getDerivative( 1, jder ) ); - } + for(unsigned i=0; i<invals.getNumberActive(); ++i) { + unsigned jder=invals.getActiveIndex(i); + outvals.addDerivative( 1, jder, dval*invals.getDerivative( 1, jder ) ); + } // Now update the outvals derivatives lists outvals.emptyActiveMembers(); - for(unsigned j=0;j<invals.getNumberActive();++j) outvals.updateIndex( invals.getActiveIndex(j) ); + for(unsigned j=0; j<invals.getNumberActive(); ++j) outvals.updateIndex( invals.getActiveIndex(j) ); outvals.completeUpdate(); return; } -void ManyRestraintsBase::apply(){ +void ManyRestraintsBase::apply() { plumed_dbg_assert( getNumberOfComponents()==1 ); getPntrToComponent(0)->addForce( -1.0*getStride() ); } diff --git a/src/manyrestraints/ManyRestraintsBase.h b/src/manyrestraints/ManyRestraintsBase.h index 9e1c3cae9..565ea340d 100644 --- a/src/manyrestraints/ManyRestraintsBase.h +++ b/src/manyrestraints/ManyRestraintsBase.h @@ -32,10 +32,10 @@ namespace PLMD { namespace manyrestraints { class ManyRestraintsBase : - public ActionWithValue, - public ActionPilot, - public vesselbase::ActionWithVessel, - public vesselbase::ActionWithInputVessel + public ActionWithValue, + public ActionPilot, + public vesselbase::ActionWithVessel, + public vesselbase::ActionWithInputVessel { private: /// Pointer to underlying action with vessel @@ -43,13 +43,13 @@ private: public: static void registerKeywords( Keywords& keys ); explicit ManyRestraintsBase(const ActionOptions&); - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } unsigned getNumberOfDerivatives(); /// Routines that have to be defined so as not to have problems with virtual methods - void deactivate_task( const unsigned & task_index ){}; -/// Don't actually clear the derivatives when this is called from plumed main. -/// They are calculated inside another action and clearing them would be bad - void clearDerivatives(){} + void deactivate_task( const unsigned & task_index ) {}; +/// Don't actually clear the derivatives when this is called from plumed main. +/// They are calculated inside another action and clearing them would be bad + void clearDerivatives() {} /// Do jobs required before tasks are undertaken void doJobsRequiredBeforeTaskList(); /// This actually does the calculation @@ -57,16 +57,16 @@ public: /// Calculate the potential virtual double calcPotential( const double& val, double& df ) const=0; // Calculate does nothing - void calculate(){}; + void calculate() {}; /// This should never be called - void performTask( const unsigned& , const unsigned& , MultiValue& ) const { plumed_error(); } + void performTask( const unsigned&, const unsigned&, MultiValue& ) const { plumed_error(); } /// Deactivate task now does nothing void apply(); - void applyBridgeForces( const std::vector<double>& bb ){ plumed_assert( bb.size()==0 ); } + void applyBridgeForces( const std::vector<double>& bb ) { plumed_assert( bb.size()==0 ); } }; inline -unsigned ManyRestraintsBase::getNumberOfDerivatives(){ +unsigned ManyRestraintsBase::getNumberOfDerivatives() { return aves->getNumberOfDerivatives(); } diff --git a/src/manyrestraints/UWalls.cpp b/src/manyrestraints/UWalls.cpp index 474eab490..f4c75f0d8 100644 --- a/src/manyrestraints/UWalls.cpp +++ b/src/manyrestraints/UWalls.cpp @@ -25,7 +25,7 @@ namespace PLMD { namespace manyrestraints { -//+PLUMEDOC MCOLVARB UWALLS +//+PLUMEDOC MCOLVARB UWALLS /* Add \ref UPPER_WALLS restraints on all the multicolvar values @@ -36,14 +36,14 @@ keyword and places a restraint on each quantity, \f$x\f$, with the following fun k((x-a+o)/s)^e \f$ -\f$k\f$ (KAPPA) is an energy constant in internal unit of the code, \f$s\f$ (EPS) a rescaling factor and +\f$k\f$ (KAPPA) is an energy constant in internal unit of the code, \f$s\f$ (EPS) a rescaling factor and \f$e\f$ (EXP) the exponent determining the power law. By default: EXP = 2, EPS = 1.0, OFF = 0. \par Examples -The following set of commands can be used to stop a cluster composed of 20 atoms subliming. The position of -the centre of mass of the cluster is calculated by the \ref COM command labelled c1. The \ref DISTANCES -command labelled d1 is then used to calculate the distance between each of the 20 atoms in the cluster +The following set of commands can be used to stop a cluster composed of 20 atoms subliming. The position of +the centre of mass of the cluster is calculated by the \ref COM command labelled c1. The \ref DISTANCES +command labelled d1 is then used to calculate the distance between each of the 20 atoms in the cluster and the center of mass of the cluster. These distances are then passed to the UWALLS command, which adds a \ref UPPER_WALLS restraint on each of them and thereby prevents each of them from moving very far from the centre of mass of the cluster. @@ -53,7 +53,7 @@ COM ATOMS=1-20 LABEL=c1 DISTANCES GROUPA=c1 GROUPB=1-20 LABEL=d1 UWALLS DATA=d1 AT=2.5 KAPPA=0.2 LABEL=sr \endverbatim - + */ //+ENDPLUMEDOC @@ -74,7 +74,7 @@ public: PLUMED_REGISTER_ACTION(UWalls,"UWALLS") -void UWalls::registerKeywords( Keywords& keys ){ +void UWalls::registerKeywords( Keywords& keys ) { ManyRestraintsBase::registerKeywords( keys ); keys.add("compulsory","AT","the radius of the sphere"); keys.add("compulsory","KAPPA","the force constant for the wall. The k_i in the expression for a wall."); @@ -84,8 +84,8 @@ void UWalls::registerKeywords( Keywords& keys ){ } UWalls::UWalls(const ActionOptions& ao): -Action(ao), -ManyRestraintsBase(ao) + Action(ao), + ManyRestraintsBase(ao) { parse("AT",at); parse("OFFSET",offset); @@ -95,13 +95,13 @@ ManyRestraintsBase(ao) checkRead(); } -double UWalls::calcPotential( const double& val, double& df ) const { +double UWalls::calcPotential( const double& val, double& df ) const { double uscale = (val - at + offset)/eps; - if( uscale > 0. ){ - double power = pow( uscale, exp ); - df = ( kappa / eps ) * exp * power / uscale; + if( uscale > 0. ) { + double power = pow( uscale, exp ); + df = ( kappa / eps ) * exp * power / uscale; - return kappa*power; + return kappa*power; } return 0.0; diff --git a/src/mapping/Mapping.cpp b/src/mapping/Mapping.cpp index ac80b6bee..c1a6dba33 100644 --- a/src/mapping/Mapping.cpp +++ b/src/mapping/Mapping.cpp @@ -31,72 +31,72 @@ namespace PLMD { namespace mapping { -void Mapping::registerKeywords( Keywords& keys ){ - Action::registerKeywords( keys ); +void Mapping::registerKeywords( Keywords& keys ) { + Action::registerKeywords( keys ); ActionWithValue::registerKeywords( keys ); - ActionWithArguments::registerKeywords( keys ); - ActionAtomistic::registerKeywords( keys ); + ActionWithArguments::registerKeywords( keys ); + ActionAtomistic::registerKeywords( keys ); vesselbase::ActionWithVessel::registerKeywords( keys ); keys.add("compulsory","REFERENCE","a pdb file containing the set of reference configurations"); keys.add("compulsory","PROPERTY","the property to be used in the index. This should be in the REMARK of the reference"); keys.add("compulsory","TYPE","OPTIMAL-FAST","the manner in which distances are calculated. More information on the different " - "metrics that are available in PLUMED can be found in the section of the manual on " - "\\ref dists"); + "metrics that are available in PLUMED can be found in the section of the manual on " + "\\ref dists"); keys.addFlag("DISABLE_CHECKS",false,"disable checks on reference input structures."); } Mapping::Mapping(const ActionOptions&ao): -Action(ao), -ActionAtomistic(ao), -ActionWithArguments(ao), -ActionWithValue(ao), -ActionWithVessel(ao) + Action(ao), + ActionAtomistic(ao), + ActionWithArguments(ao), + ActionWithValue(ao), + ActionWithVessel(ao) { // Read the input std::string mtype; parse("TYPE",mtype); bool skipchecks; parseFlag("DISABLE_CHECKS",skipchecks); // Setup the object that does the mapping - mymap = new PointWiseMapping( mtype, skipchecks ); - + mymap = new PointWiseMapping( mtype, skipchecks ); + // Read the properties we require - if( keywords.exists("PROPERTY") ){ - std::vector<std::string> property; - parseVector("PROPERTY",property); - if(property.size()==0) error("no properties were specified"); - mymap->setPropertyNames( property, false ); + if( keywords.exists("PROPERTY") ) { + std::vector<std::string> property; + parseVector("PROPERTY",property); + if(property.size()==0) error("no properties were specified"); + mymap->setPropertyNames( property, false ); } else { - std::vector<std::string> property(1); - property[0]="spath"; - mymap->setPropertyNames( property, true ); + std::vector<std::string> property(1); + property[0]="spath"; + mymap->setPropertyNames( property, true ); } // Open reference file - std::string reference; parse("REFERENCE",reference); - FILE* fp=fopen(reference.c_str(),"r"); + std::string reference; parse("REFERENCE",reference); + FILE* fp=fopen(reference.c_str(),"r"); if(!fp) error("could not open reference file " + reference ); - // Read all reference configurations - bool do_read=true; std::vector<double> weights; + // Read all reference configurations + bool do_read=true; std::vector<double> weights; unsigned nfram=0, wnorm=0., ww; - while (do_read){ - PDB mypdb; - // Read the pdb file - do_read=mypdb.readFromFilepointer(fp,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength()); - // Fix argument names - expandArgKeywordInPDB( mypdb ); - if(do_read){ - mymap->readFrame( mypdb ); ww=mymap->getWeight( nfram ); - weights.push_back( ww ); - wnorm+=ww; nfram++; - } else { - break; - } + while (do_read) { + PDB mypdb; + // Read the pdb file + do_read=mypdb.readFromFilepointer(fp,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength()); + // Fix argument names + expandArgKeywordInPDB( mypdb ); + if(do_read) { + mymap->readFrame( mypdb ); ww=mymap->getWeight( nfram ); + weights.push_back( ww ); + wnorm+=ww; nfram++; + } else { + break; + } } - fclose(fp); + fclose(fp); if(nfram==0 ) error("no reference configurations were specified"); log.printf(" found %u configurations in file %s\n",nfram,reference.c_str() ); - for(unsigned i=0;i<weights.size();++i) weights[i] /= wnorm; + for(unsigned i=0; i<weights.size(); ++i) weights[i] /= wnorm; mymap->setWeights( weights ); // Finish the setup of the mapping object @@ -106,49 +106,49 @@ ActionWithVessel(ao) requestAtoms( atoms ); std::vector<Value*> req_args; interpretArgumentList( args, req_args ); requestArguments( req_args ); // Duplicate all frames (duplicates are used by sketch-map) - // mymap->duplicateFrameList(); + // mymap->duplicateFrameList(); // fframes.resize( 2*nfram, 0.0 ); dfframes.resize( 2*nfram, 0.0 ); // plumed_assert( !mymap->mappingNeedsSetup() ); // Resize all derivative arrays // mymap->setNumberOfAtomsAndArguments( atoms.size(), args.size() ); // Resize forces array - if( getNumberOfAtoms()>0 ){ - forcesToApply.resize( 3*getNumberOfAtoms() + 9 + getNumberOfArguments() ); + if( getNumberOfAtoms()>0 ) { + forcesToApply.resize( 3*getNumberOfAtoms() + 9 + getNumberOfArguments() ); } else { - forcesToApply.resize( getNumberOfArguments() ); + forcesToApply.resize( getNumberOfArguments() ); } } -void Mapping::turnOnDerivatives(){ +void Mapping::turnOnDerivatives() { ActionWithValue::turnOnDerivatives(); needsDerivatives(); -} +} -Mapping::~Mapping(){ +Mapping::~Mapping() { delete mymap; } -void Mapping::prepare(){ - if( mymap->mappingNeedsSetup() ){ - // Get the arguments and atoms that are required - std::vector<AtomNumber> atoms; std::vector<std::string> args; - mymap->getAtomAndArgumentRequirements( atoms, args ); - requestAtoms( atoms ); std::vector<Value*> req_args; - interpretArgumentList( args, req_args ); requestArguments( req_args ); - // Duplicate all frames (duplicates are used by sketch-map) - //mymap->duplicateFrameList(); - // Get the number of frames in the path - // unsigned nfram=getNumberOfReferencePoints(); - // fframes.resize( 2*nfram, 0.0 ); dfframes.resize( 2*nfram, 0.0 ); - // plumed_assert( !mymap->mappingNeedsSetup() ); - // Resize all derivative arrays - // mymap->setNumberOfAtomsAndArguments( atoms.size(), args.size() ); - // Resize forces array - if( getNumberOfAtoms()>0 ){ - forcesToApply.resize( 3*getNumberOfAtoms() + 9 + getNumberOfArguments() ); - } else { - forcesToApply.resize( getNumberOfArguments() ); - } +void Mapping::prepare() { + if( mymap->mappingNeedsSetup() ) { + // Get the arguments and atoms that are required + std::vector<AtomNumber> atoms; std::vector<std::string> args; + mymap->getAtomAndArgumentRequirements( atoms, args ); + requestAtoms( atoms ); std::vector<Value*> req_args; + interpretArgumentList( args, req_args ); requestArguments( req_args ); + // Duplicate all frames (duplicates are used by sketch-map) + //mymap->duplicateFrameList(); + // Get the number of frames in the path + // unsigned nfram=getNumberOfReferencePoints(); + // fframes.resize( 2*nfram, 0.0 ); dfframes.resize( 2*nfram, 0.0 ); + // plumed_assert( !mymap->mappingNeedsSetup() ); + // Resize all derivative arrays + // mymap->setNumberOfAtomsAndArguments( atoms.size(), args.size() ); + // Resize forces array + if( getNumberOfAtoms()>0 ) { + forcesToApply.resize( 3*getNumberOfAtoms() + 9 + getNumberOfArguments() ); + } else { + forcesToApply.resize( getNumberOfArguments() ); + } } } @@ -156,72 +156,72 @@ unsigned Mapping::getPropertyIndex( const std::string& name ) const { return mymap->getPropertyIndex( name ); } -void Mapping::setPropertyValue( const unsigned& iframe, const unsigned& jprop, const double& property ){ +void Mapping::setPropertyValue( const unsigned& iframe, const unsigned& jprop, const double& property ) { mymap->setProjectionCoordinate( iframe, jprop, property ); } -double Mapping::getLambda(){ +double Mapping::getLambda() { plumed_merror("lambda is not defined in this mapping type"); } -std::string Mapping::getArgumentName( unsigned& iarg ){ +std::string Mapping::getArgumentName( unsigned& iarg ) { if( iarg < getNumberOfArguments() ) return getPntrToArgument(iarg)->getName(); unsigned iatom=iarg - getNumberOfArguments(); std::string atnum; Tools::convert( getAbsoluteIndex(iatom).serial(),atnum); unsigned icomp=iatom%3; if(icomp==0) return "pos" + atnum + "x"; if(icomp==1) return "pos" + atnum + "y"; - return "pos" + atnum + "z"; -} + return "pos" + atnum + "z"; +} void Mapping::finishPackSetup( const unsigned& ifunc, ReferenceValuePack& mypack ) const { - ReferenceConfiguration* myref=mymap->getFrame(ifunc); mypack.setValIndex(0); - unsigned nargs2=myref->getNumberOfReferenceArguments(); unsigned nat2=myref->getNumberOfReferencePositions(); - if( mypack.getNumberOfAtoms()!=nat2 || mypack.getNumberOfArguments()!=nargs2 ) mypack.resize( nargs2, nat2 ); - if( nat2>0 ){ - ReferenceAtoms* myat2=dynamic_cast<ReferenceAtoms*>( myref ); plumed_dbg_assert( myat2 ); - for(unsigned i=0;i<nat2;++i) mypack.setAtomIndex( i, myat2->getAtomIndex(i) ); - } + ReferenceConfiguration* myref=mymap->getFrame(ifunc); mypack.setValIndex(0); + unsigned nargs2=myref->getNumberOfReferenceArguments(); unsigned nat2=myref->getNumberOfReferencePositions(); + if( mypack.getNumberOfAtoms()!=nat2 || mypack.getNumberOfArguments()!=nargs2 ) mypack.resize( nargs2, nat2 ); + if( nat2>0 ) { + ReferenceAtoms* myat2=dynamic_cast<ReferenceAtoms*>( myref ); plumed_dbg_assert( myat2 ); + for(unsigned i=0; i<nat2; ++i) mypack.setAtomIndex( i, myat2->getAtomIndex(i) ); + } } double Mapping::calculateDistanceFunction( const unsigned& ifunc, ReferenceValuePack& myder, const bool& squared ) const { // Calculate the distance - double dd = mymap->calcDistanceFromConfiguration( ifunc, getPositions(), getPbc(), getArguments(), myder, squared ); + double dd = mymap->calcDistanceFromConfiguration( ifunc, getPositions(), getPbc(), getArguments(), myder, squared ); // Transform distance by whatever double df, ff=transformHD( dd, df ); myder.scaleAllDerivatives( df ); // And the virial - if( getNumberOfAtoms()>0 && !myder.virialWasSet() ){ - Tensor tvir; tvir.zero(); - for(unsigned i=0;i<myder.getNumberOfAtoms();++i) tvir +=-1.0*Tensor( getPosition( myder.getAtomIndex(i) ), myder.getAtomDerivative(i) ); - myder.addBoxDerivatives( tvir ); + if( getNumberOfAtoms()>0 && !myder.virialWasSet() ) { + Tensor tvir; tvir.zero(); + for(unsigned i=0; i<myder.getNumberOfAtoms(); ++i) tvir +=-1.0*Tensor( getPosition( myder.getAtomIndex(i) ), myder.getAtomDerivative(i) ); + myder.addBoxDerivatives( tvir ); } return ff; } -ReferenceConfiguration* Mapping::getReferenceConfiguration( const unsigned& ifunc ){ +ReferenceConfiguration* Mapping::getReferenceConfiguration( const unsigned& ifunc ) { return mymap->getFrame( ifunc ); } -void Mapping::calculateNumericalDerivatives( ActionWithValue* a ){ - if( getNumberOfArguments()>0 ){ - ActionWithArguments::calculateNumericalDerivatives( a ); +void Mapping::calculateNumericalDerivatives( ActionWithValue* a ) { + if( getNumberOfArguments()>0 ) { + ActionWithArguments::calculateNumericalDerivatives( a ); } - if( getNumberOfAtoms()>0 ){ - Matrix<double> save_derivatives( getNumberOfComponents(), getNumberOfArguments() ); - for(unsigned j=0;j<getNumberOfComponents();++j){ - for(unsigned i=0;i<getNumberOfArguments();++i) save_derivatives(j,i)=getPntrToComponent(j)->getDerivative(i); - } - calculateAtomicNumericalDerivatives( a, getNumberOfArguments() ); - for(unsigned j=0;j<getNumberOfComponents();++j){ - for(unsigned i=0;i<getNumberOfArguments();++i) getPntrToComponent(j)->addDerivative( i, save_derivatives(j,i) ); - } + if( getNumberOfAtoms()>0 ) { + Matrix<double> save_derivatives( getNumberOfComponents(), getNumberOfArguments() ); + for(unsigned j=0; j<getNumberOfComponents(); ++j) { + for(unsigned i=0; i<getNumberOfArguments(); ++i) save_derivatives(j,i)=getPntrToComponent(j)->getDerivative(i); + } + calculateAtomicNumericalDerivatives( a, getNumberOfArguments() ); + for(unsigned j=0; j<getNumberOfComponents(); ++j) { + for(unsigned i=0; i<getNumberOfArguments(); ++i) getPntrToComponent(j)->addDerivative( i, save_derivatives(j,i) ); + } } } -void Mapping::apply(){ - if( getForcesFromVessels( forcesToApply ) ){ - addForcesOnArguments( forcesToApply ); - if( getNumberOfAtoms()>0 ) setForcesOnAtoms( forcesToApply, getNumberOfArguments() ); +void Mapping::apply() { + if( getForcesFromVessels( forcesToApply ) ) { + addForcesOnArguments( forcesToApply ); + if( getNumberOfAtoms()>0 ) setForcesOnAtoms( forcesToApply, getNumberOfArguments() ); } } diff --git a/src/mapping/Mapping.h b/src/mapping/Mapping.h index 9b3145129..02299d4c3 100644 --- a/src/mapping/Mapping.h +++ b/src/mapping/Mapping.h @@ -40,8 +40,8 @@ class Mapping : public ActionWithArguments, public ActionWithValue, public vesselbase::ActionWithVessel - { -friend class TrigonometricPathVessel; +{ + friend class TrigonometricPathVessel; private: // The derivative wrt to the distance from the frame std::vector<double> dfframes; @@ -76,10 +76,10 @@ public: void lockRequests(); void unlockRequests(); /// Distance from a point is never periodic - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } /// Get the number of derivatives for this action unsigned getNumberOfDerivatives(); // N.B. This is replacing the virtual function in ActionWithValue -/// Get the value of lambda for paths and property maps +/// Get the value of lambda for paths and property maps virtual double getLambda(); /// This does the transformation of the distance by whatever function is required virtual double transformHD( const double& dist, double& df ) const=0; @@ -87,7 +87,7 @@ public: unsigned getNumberOfProperties() const ; /// Get the name of the ith property we are projecting std::string getPropertyName( const unsigned& iprop ) const ; -/// Get the index of a particular named property +/// Get the index of a particular named property unsigned getPropertyIndex( const std::string& name ) const ; /// Set the value of one of the projection coordinates void setPropertyValue( const unsigned& iframe, const unsigned& iprop, const double& property ); @@ -97,57 +97,57 @@ public: double getPropertyValue( const unsigned& current, const unsigned& iprop ) const ; /// Stuff to do before we do the calculation void prepare(); -/// Apply the forces +/// Apply the forces void apply(); }; inline unsigned Mapping::getNumberOfReferencePoints() const { - return mymap->getNumberOfMappedPoints(); + return mymap->getNumberOfMappedPoints(); } inline -unsigned Mapping::getNumberOfDerivatives(){ +unsigned Mapping::getNumberOfDerivatives() { unsigned nat=getNumberOfAtoms(); if(nat>0) return 3*nat + 9 + getNumberOfArguments(); return getNumberOfArguments(); } inline -void Mapping::lockRequests(){ +void Mapping::lockRequests() { ActionWithArguments::lockRequests(); ActionAtomistic::lockRequests(); } inline -void Mapping::unlockRequests(){ +void Mapping::unlockRequests() { ActionWithArguments::unlockRequests(); ActionAtomistic::unlockRequests(); } inline unsigned Mapping::getNumberOfProperties() const { - return mymap->getNumberOfProperties(); + return mymap->getNumberOfProperties(); } inline std::string Mapping::getPropertyName( const unsigned& iprop ) const { - return mymap->getPropertyName(iprop); + return mymap->getPropertyName(iprop); } inline double Mapping::getPropertyValue( const unsigned& cur, const unsigned& iprop ) const { plumed_dbg_assert( iprop<getNumberOfProperties() ); - return mymap->getPropertyValue( cur, iprop ); + return mymap->getPropertyValue( cur, iprop ); } inline double Mapping::getWeight( const unsigned& current ) const { - return mymap->getWeight( current ); + return mymap->getWeight( current ); } inline -void Mapping::storeDistanceFunction( const unsigned& ifunc ){ +void Mapping::storeDistanceFunction( const unsigned& ifunc ) { plumed_dbg_assert( ifunc<getNumberOfReferencePoints() ); unsigned storef=getNumberOfReferencePoints()+ifunc; fframes[storef]=fframes[ifunc]; dfframes[storef]=dfframes[ifunc]; @@ -155,7 +155,7 @@ void Mapping::storeDistanceFunction( const unsigned& ifunc ){ } inline -std::vector<ReferenceConfiguration*>& Mapping::getAllReferenceConfigurations(){ +std::vector<ReferenceConfiguration*>& Mapping::getAllReferenceConfigurations() { return mymap->getReferenceConfigurations(); } diff --git a/src/mapping/PCAVars.cpp b/src/mapping/PCAVars.cpp index 0ae940a74..d029720ed 100644 --- a/src/mapping/PCAVars.cpp +++ b/src/mapping/PCAVars.cpp @@ -33,25 +33,25 @@ /* Projection on principal component eigenvectors or other high dimensional linear subspace -The collective variables described in \ref dists allow one to calculate the distance between the -instaneous structure adopted by the system and some high-dimensional, reference configuration. The +The collective variables described in \ref dists allow one to calculate the distance between the +instaneous structure adopted by the system and some high-dimensional, reference configuration. The problem with doing this is that, as one gets further and further from the reference configuration, the distance from it becomes a progressively poorer and poorer collective variable. This happens because -the ``number" of structures at a distance \f$d\f$ from a reference configuration is proportional to \f$d^N\f$ in -an \f$N\f$ dimensional space. Consequently, when \f$d\f$ is small the distance from the reference configuration +the ``number" of structures at a distance \f$d\f$ from a reference configuration is proportional to \f$d^N\f$ in +an \f$N\f$ dimensional space. Consequently, when \f$d\f$ is small the distance from the reference configuration may well be a good collective variable. However, when \f$d\f$ is large it is unlikely that the distance from the reference -structure is a good CV. When the distance is large there will almost certainly be markedly different -configuration that have the same CV value and hence barriers in transverse degrees of -freedom. +structure is a good CV. When the distance is large there will almost certainly be markedly different +configuration that have the same CV value and hence barriers in transverse degrees of +freedom. -For these reasons dimensionality reduction is often employed so a projection \f$\mathbf{s}\f$ of a high-dimensional configuration +For these reasons dimensionality reduction is often employed so a projection \f$\mathbf{s}\f$ of a high-dimensional configuration \f$\mathbf{X}\f$ in a lower dimensionality space using a function: \f[ \mathbf{s} = F(\mathbf{X}-\mathbf{X}^{ref}) \f] -where here we have introduced some high-dimensional reference configuration \f$\mathbf{X}^{ref}\f$. By far the simplest way to +where here we have introduced some high-dimensional reference configuration \f$\mathbf{X}^{ref}\f$. By far the simplest way to do this is to use some linear operator for \f$F\f$. That is to say we find a low-dimensional projection by rotating the basis vectors using some linear algebra: @@ -61,9 +61,9 @@ by rotating the basis vectors using some linear algebra: Here \f$A\f$ is a \f$d\f$ by \f$D\f$ matrix where \f$D\f$ is the dimensionality of the high dimensional space and \f$d\f$ is the dimensionality of the lower dimensional subspace. In plumed when this kind of projection you can use the majority -of the metrics detailed on \ref dists to calculate the displacement, \f$\mathbf{X}-\mathbf{X}^{ref}\f$, from the reference configuration. -The matrix \f$A\f$ can be found by various means including principal component analysis and normal mode analysis. In both these methods the -rows of \f$A\f$ would be the principle eigenvectors of a square matrix. For PCA the covariance while for normal modes the Hessian. +of the metrics detailed on \ref dists to calculate the displacement, \f$\mathbf{X}-\mathbf{X}^{ref}\f$, from the reference configuration. +The matrix \f$A\f$ can be found by various means including principal component analysis and normal mode analysis. In both these methods the +rows of \f$A\f$ would be the principle eigenvectors of a square matrix. For PCA the covariance while for normal modes the Hessian. \bug It is not possible to use the \ref DRMSD metric with this variable. You can get around this by listing the set of distances you wish to calculate for your DRMSD in the plumed file explicitally and using the EUCLIDEAN metric. MAHALONOBIS and NORM-EUCLIDEAN also do not work with this variable but using these options makes little sense when projecting on a linear subspace. @@ -72,19 +72,19 @@ rows of \f$A\f$ would be the principle eigenvectors of a square matrix. For PCA The following input calculates a projection on a linear subspace where the displacements from the reference configuration are calculated using the OPTIMAL metric. Consequently, both translation of the center of mass of the atoms and rotation of the reference -frame are removed from these displacements. The matrix \f$A\f$ and the reference -configuration \f$R^{ref}\f$ are specified in the pdb input file reference.pdb and the +frame are removed from these displacements. The matrix \f$A\f$ and the reference +configuration \f$R^{ref}\f$ are specified in the pdb input file reference.pdb and the value of all projections (and the residual) are output to a file called colvar2. \verbatim PCAVARS REFERENCE=reference.pdb TYPE=OPTIMAL LABEL=pca2 -PRINT ARG=pca2.* FILE=colvar2 +PRINT ARG=pca2.* FILE=colvar2 \endverbatim The reference configurations can be specified using a pdb file. The first configuration that you provide is the reference configuration, -which is refered to in the above as \f$X^{ref}\f$ subsequent configurations give the directions of row vectors that are contained in -the matrix \f$A\f$ above. These directions can be specified by specifying a second configuration - in this case a vector will -be constructed by calculating the displacement of this second configuration from the reference configuration. A pdb input prepared +which is refered to in the above as \f$X^{ref}\f$ subsequent configurations give the directions of row vectors that are contained in +the matrix \f$A\f$ above. These directions can be specified by specifying a second configuration - in this case a vector will +be constructed by calculating the displacement of this second configuration from the reference configuration. A pdb input prepared in this way would look as follows: \verbatim @@ -106,7 +106,7 @@ ATOM 21 HH32 NME 3 18.572 -13.148 -16.346 1.00 1.00 END \endverbatim -Alternatively, the second configuration can specify the components of \f$A\f$ explicitally. In this case you need to include the +Alternatively, the second configuration can specify the components of \f$A\f$ explicitally. In this case you need to include the keyword TYPE=DIRECTION in the remarks to the pdb as shown below. \verbatim @@ -134,12 +134,12 @@ for each of the frames of your path. An input file in this case might look like \verbatim DESCRIPTION: a pca eigenvector specified using the start point and direction in the HD space. -REMARK WEIGHT=1.0 -REMARK ARG=d1,d2 +REMARK WEIGHT=1.0 +REMARK ARG=d1,d2 REMARK d1=1.0 d2=1.0 END REMARK TYPE=DIRECTION -REMARK ARG=d1,d2 +REMARK ARG=d1,d2 REMARK d1=0.1 d2=0.25 END \endverbatim @@ -151,11 +151,11 @@ If we wanted to specify the direction in this metric using the start and end poi \verbatim DESCRIPTION: a pca eigenvector specified using the start and end point of a vector in the HD space. -REMARK WEIGHT=1.0 -REMARK ARG=d1,d2 +REMARK WEIGHT=1.0 +REMARK ARG=d1,d2 REMARK d1=1.0 d2=1.0 END -REMARK ARG=d1,d2 +REMARK ARG=d1,d2 REMARK d1=1.1 d2=1.25 END \endverbatim @@ -170,13 +170,13 @@ class PCAVars : public ActionWithValue, public ActionAtomistic, public ActionWithArguments - { +{ private: /// The holders for the derivatives MultiValue myvals; ReferenceValuePack mypack; /// The position of the reference configuration (the one we align to) - ReferenceConfiguration* myref; + ReferenceConfiguration* myref; /// The eigenvectors we are interested in std::vector<Direction> directions; /// Stuff for applying forces @@ -195,30 +195,30 @@ public: PLUMED_REGISTER_ACTION(PCAVars,"PCAVARS") -void PCAVars::registerKeywords( Keywords& keys ){ +void PCAVars::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionWithValue::registerKeywords( keys ); ActionAtomistic::registerKeywords( keys ); ActionWithArguments::registerKeywords( keys ); componentsAreNotOptional(keys); - keys.addOutputComponent("eig","default","the projections on each eigenvalue are stored on values labeled eig-1, eig-2, ..."); + keys.addOutputComponent("eig","default","the projections on each eigenvalue are stored on values labeled eig-1, eig-2, ..."); keys.addOutputComponent("residual","default","the distance of the configuration from the linear subspace defined " - "by the vectors, \\f$e_i\\f$, that are contained in the rows of \\f$A\\f$. In other words this is " - "\\f$\\sqrt( r^2 - \\sum_i [\\mathbf{r}.\\mathbf{e_i}]^2)\\f$ where " - "\\f$r\\f$ is the distance between the instantaneous position and the " - "reference point."); + "by the vectors, \\f$e_i\\f$, that are contained in the rows of \\f$A\\f$. In other words this is " + "\\f$\\sqrt( r^2 - \\sum_i [\\mathbf{r}.\\mathbf{e_i}]^2)\\f$ where " + "\\f$r\\f$ is the distance between the instantaneous position and the " + "reference point."); keys.add("compulsory","REFERENCE","a pdb file containing the reference configuration and configurations that define the directions for each eigenvector"); keys.add("compulsory","TYPE","OPTIMAL","The method we are using for alignment to the reference structure"); keys.addFlag("NORMALIZE",false,"calculate the length of the eigenvector input and divide the components by it so as to have a normalised vector"); } PCAVars::PCAVars(const ActionOptions& ao): -Action(ao), -ActionWithValue(ao), -ActionAtomistic(ao), -ActionWithArguments(ao), -myvals(1,0), -mypack(0,0,myvals) + Action(ao), + ActionWithValue(ao), + ActionAtomistic(ao), + ActionWithArguments(ao), + myvals(1,0), + mypack(0,0,myvals) { // What type of distance are we calculating @@ -229,30 +229,30 @@ mypack(0,0,myvals) FILE* fp=fopen(reference.c_str(),"r"); if(!fp) error("could not open reference file " + reference ); - // Read all reference configurations + // Read all reference configurations MultiReferenceBase myframes( "", false ); bool do_read=true; unsigned nfram=0; - while (do_read){ - PDB mypdb; - // Read the pdb file - do_read=mypdb.readFromFilepointer(fp,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength()); - // Fix argument names - expandArgKeywordInPDB( mypdb ); - if(do_read){ - if( nfram==0 ){ - myref = metricRegister().create<ReferenceConfiguration>( mtype, mypdb ); - Direction* tdir = dynamic_cast<Direction*>( myref ); - if( tdir ) error("first frame should be reference configuration - not direction of vector"); - if( !myref->pcaIsEnabledForThisReference() ) error("can't do PCA with reference type " + mtype ); - std::vector<std::string> remarks( mypdb.getRemark() ); std::string rtype; - bool found=Tools::parse( remarks, "TYPE", rtype ); - if(!found){ std::vector<std::string> newrem(1); newrem[0]="TYPE="+mtype; mypdb.addRemark(newrem); } - myframes.readFrame( mypdb ); - } else myframes.readFrame( mypdb ); - nfram++; - } else { - break; - } + while (do_read) { + PDB mypdb; + // Read the pdb file + do_read=mypdb.readFromFilepointer(fp,plumed.getAtoms().usingNaturalUnits(),0.1/atoms.getUnits().getLength()); + // Fix argument names + expandArgKeywordInPDB( mypdb ); + if(do_read) { + if( nfram==0 ) { + myref = metricRegister().create<ReferenceConfiguration>( mtype, mypdb ); + Direction* tdir = dynamic_cast<Direction*>( myref ); + if( tdir ) error("first frame should be reference configuration - not direction of vector"); + if( !myref->pcaIsEnabledForThisReference() ) error("can't do PCA with reference type " + mtype ); + std::vector<std::string> remarks( mypdb.getRemark() ); std::string rtype; + bool found=Tools::parse( remarks, "TYPE", rtype ); + if(!found) { std::vector<std::string> newrem(1); newrem[0]="TYPE="+mtype; mypdb.addRemark(newrem); } + myframes.readFrame( mypdb ); + } else myframes.readFrame( mypdb ); + nfram++; + } else { + break; + } } fclose(fp); @@ -267,170 +267,170 @@ mypack(0,0,myvals) interpretArgumentList( args, req_args ); requestArguments( req_args ); // Setup the derivative pack - if( atoms.size()>0 ) myvals.resize( 1, args.size() + 3*atoms.size() + 9 ); + if( atoms.size()>0 ) myvals.resize( 1, args.size() + 3*atoms.size() + 9 ); else myvals.resize( 1, args.size() ); - mypack.resize( args.size(), atoms.size() ); - for(unsigned i=0;i<atoms.size();++i) mypack.setAtomIndex( i, i ); + mypack.resize( args.size(), atoms.size() ); + for(unsigned i=0; i<atoms.size(); ++i) mypack.setAtomIndex( i, i ); /// This sets up all the storage data required by PCA in the pack myframes.getFrame(0)->setupPCAStorage( mypack ); // Retrieve the position of the first frame, as we use this for alignment myref->setNamesAndAtomNumbers( atoms, args ); // Check there are no periodic arguments - for(unsigned i=0;i<getNumberOfArguments();++i){ - if( getPntrToArgument(i)->isPeriodic() ) error("cannot use periodic variables in pca projections"); + for(unsigned i=0; i<getNumberOfArguments(); ++i) { + if( getPntrToArgument(i)->isPeriodic() ) error("cannot use periodic variables in pca projections"); } // Work out if the user wants to normalise the input vector bool nflag; parseFlag("NORMALIZE",nflag); checkRead(); - // Resize the matrices that will hold our eivenvectors - for(unsigned i=1;i<nfram;++i){ - directions.push_back( Direction(ReferenceConfigurationOptions("DIRECTION"))); - directions[i-1].setNamesAndAtomNumbers( atoms, args ); + // Resize the matrices that will hold our eivenvectors + for(unsigned i=1; i<nfram; ++i) { + directions.push_back( Direction(ReferenceConfigurationOptions("DIRECTION"))); + directions[i-1].setNamesAndAtomNumbers( atoms, args ); } // Create fake periodic boundary condition (these would only be used for DRMSD which is not allowed) - // Now calculate the eigenvectors - for(unsigned i=1;i<nfram;++i){ - myframes.getFrame(i)->extractDisplacementVector( myref->getReferencePositions(), getArguments(), myref->getReferenceArguments(), false, nflag, directions[i-1] ); - // Create a component to store the output - std::string num; Tools::convert( i, num ); - addComponentWithDerivatives("eig-"+num); componentIsNotPeriodic("eig-"+num); + // Now calculate the eigenvectors + for(unsigned i=1; i<nfram; ++i) { + myframes.getFrame(i)->extractDisplacementVector( myref->getReferencePositions(), getArguments(), myref->getReferenceArguments(), false, nflag, directions[i-1] ); + // Create a component to store the output + std::string num; Tools::convert( i, num ); + addComponentWithDerivatives("eig-"+num); componentIsNotPeriodic("eig-"+num); } addComponentWithDerivatives("residual"); componentIsNotPeriodic("residual"); // Get appropriate number of derivatives unsigned nder; - if( getNumberOfAtoms()>0 ){ - nder = 3*getNumberOfAtoms() + 9 + getNumberOfArguments(); + if( getNumberOfAtoms()>0 ) { + nder = 3*getNumberOfAtoms() + 9 + getNumberOfArguments(); } else { - nder = getNumberOfArguments(); + nder = getNumberOfArguments(); } // Resize all derivative arrays - forces.resize( nder ); forcesToApply.resize( nder ); - for(unsigned i=0;i<getNumberOfComponents();++i) getPntrToComponent(i)->resizeDerivatives(nder); + forces.resize( nder ); forcesToApply.resize( nder ); + for(unsigned i=0; i<getNumberOfComponents(); ++i) getPntrToComponent(i)->resizeDerivatives(nder); } -PCAVars::~PCAVars(){ - delete myref; +PCAVars::~PCAVars() { + delete myref; } -unsigned PCAVars::getNumberOfDerivatives(){ - if( getNumberOfAtoms()>0 ){ - return 3*getNumberOfAtoms() + 9 + getNumberOfArguments(); - } +unsigned PCAVars::getNumberOfDerivatives() { + if( getNumberOfAtoms()>0 ) { + return 3*getNumberOfAtoms() + 9 + getNumberOfArguments(); + } return getNumberOfArguments(); -} +} -void PCAVars::lockRequests(){ +void PCAVars::lockRequests() { ActionWithArguments::lockRequests(); ActionAtomistic::lockRequests(); } -void PCAVars::unlockRequests(){ - ActionWithArguments::unlockRequests(); +void PCAVars::unlockRequests() { + ActionWithArguments::unlockRequests(); ActionAtomistic::unlockRequests(); -} +} -void PCAVars::calculate(){ +void PCAVars::calculate() { // Clear the reference value pack mypack.clear(); // Calculate distance between instaneous configuration and reference double dist = myref->calculate( getPositions(), getPbc(), getArguments(), mypack, true ); - + // Start accumulating residual by adding derivatives of distance Value* resid=getPntrToComponent( getNumberOfComponents()-1 ); unsigned nargs=getNumberOfArguments(); - for(unsigned j=0;j<getNumberOfArguments();++j) resid->addDerivative( j, mypack.getArgumentDerivative(j) ); - for(unsigned j=0;j<getNumberOfAtoms();++j){ - Vector ader=mypack.getAtomDerivative( j ); - for(unsigned k=0;k<3;++k) resid->addDerivative( nargs +3*j+k, ader[k] ); + for(unsigned j=0; j<getNumberOfArguments(); ++j) resid->addDerivative( j, mypack.getArgumentDerivative(j) ); + for(unsigned j=0; j<getNumberOfAtoms(); ++j) { + Vector ader=mypack.getAtomDerivative( j ); + for(unsigned k=0; k<3; ++k) resid->addDerivative( nargs +3*j+k, ader[k] ); } // Retrieve the values of all arguments - std::vector<double> args( getNumberOfArguments() ); for(unsigned i=0;i<getNumberOfArguments();++i) args[i]=getArgument(i); + std::vector<double> args( getNumberOfArguments() ); for(unsigned i=0; i<getNumberOfArguments(); ++i) args[i]=getArgument(i); // Now calculate projections on pca vectors Vector adif, ader; Tensor fvir, tvir; - for(unsigned i=0;i<getNumberOfComponents()-1;++i){ // One less component as we also have residual - double proj=myref->projectDisplacementOnVector( directions[i], getPositions(), getArguments(), args, mypack ); - - // And now accumulate derivatives - Value* eid=getPntrToComponent(i); - for(unsigned j=0;j<getNumberOfArguments();++j) eid->addDerivative( j, mypack.getArgumentDerivative(j) ); - if( getNumberOfAtoms()>0 ){ - tvir.zero(); - for(unsigned j=0;j<getNumberOfAtoms();++j){ - Vector myader=mypack.getAtomDerivative(j); - for(unsigned k=0;k<3;++k){ - eid->addDerivative( nargs + 3*j+k, myader[k] ); - resid->addDerivative( nargs + 3*j+k, -2*proj*myader[k] ); - } - tvir += -1.0*Tensor( getPosition(j), myader ); - } - for(unsigned j=0;j<3;++j){ - for(unsigned k=0;k<3;++k) eid->addDerivative( nargs + 3*getNumberOfAtoms() + 3*j + k, tvir(j,k) ); - } + for(unsigned i=0; i<getNumberOfComponents()-1; ++i) { // One less component as we also have residual + double proj=myref->projectDisplacementOnVector( directions[i], getPositions(), getArguments(), args, mypack ); + + // And now accumulate derivatives + Value* eid=getPntrToComponent(i); + for(unsigned j=0; j<getNumberOfArguments(); ++j) eid->addDerivative( j, mypack.getArgumentDerivative(j) ); + if( getNumberOfAtoms()>0 ) { + tvir.zero(); + for(unsigned j=0; j<getNumberOfAtoms(); ++j) { + Vector myader=mypack.getAtomDerivative(j); + for(unsigned k=0; k<3; ++k) { + eid->addDerivative( nargs + 3*j+k, myader[k] ); + resid->addDerivative( nargs + 3*j+k, -2*proj*myader[k] ); + } + tvir += -1.0*Tensor( getPosition(j), myader ); + } + for(unsigned j=0; j<3; ++j) { + for(unsigned k=0; k<3; ++k) eid->addDerivative( nargs + 3*getNumberOfAtoms() + 3*j + k, tvir(j,k) ); } - dist -= proj*proj; // Subtract square from total squared distance to get residual squared - // Derivatives of residual - for(unsigned j=0;j<getNumberOfArguments();++j) resid->addDerivative( j, -2*proj*eid->getDerivative(j) ); - // for(unsigned j=0;j<getNumberOfArguments();++j) resid->addDerivative( j, -2*proj*arg_eigv(i,j) ); - // And set final value - getPntrToComponent(i)->set( proj ); + } + dist -= proj*proj; // Subtract square from total squared distance to get residual squared + // Derivatives of residual + for(unsigned j=0; j<getNumberOfArguments(); ++j) resid->addDerivative( j, -2*proj*eid->getDerivative(j) ); + // for(unsigned j=0;j<getNumberOfArguments();++j) resid->addDerivative( j, -2*proj*arg_eigv(i,j) ); + // And set final value + getPntrToComponent(i)->set( proj ); } dist=sqrt(dist); resid->set( dist ); // Take square root of residual derivatives double prefactor = 0.5 / dist; - for(unsigned j=0;j<getNumberOfArguments();++j) resid->setDerivative( j, prefactor*resid->getDerivative(j) ); - for(unsigned j=0;j<getNumberOfAtoms();++j){ - for(unsigned k=0;k<3;++k) resid->setDerivative( nargs + 3*j+k, prefactor*resid->getDerivative( nargs+3*j+k ) ); + for(unsigned j=0; j<getNumberOfArguments(); ++j) resid->setDerivative( j, prefactor*resid->getDerivative(j) ); + for(unsigned j=0; j<getNumberOfAtoms(); ++j) { + for(unsigned k=0; k<3; ++k) resid->setDerivative( nargs + 3*j+k, prefactor*resid->getDerivative( nargs+3*j+k ) ); } // And finally virial for residual - if( getNumberOfAtoms()>0 ){ - tvir.zero(); - for(unsigned j=0;j<getNumberOfAtoms();++j){ - Vector ader; for(unsigned k=0;k<3;++k) ader[k]=resid->getDerivative( nargs + 3*j+k ); - tvir += -1.0*Tensor( getPosition(j), ader ); - } - for(unsigned j=0;j<3;++j){ - for(unsigned k=0;k<3;++k) resid->addDerivative( nargs + 3*getNumberOfAtoms() + 3*j + k, tvir(j,k) ); - } + if( getNumberOfAtoms()>0 ) { + tvir.zero(); + for(unsigned j=0; j<getNumberOfAtoms(); ++j) { + Vector ader; for(unsigned k=0; k<3; ++k) ader[k]=resid->getDerivative( nargs + 3*j+k ); + tvir += -1.0*Tensor( getPosition(j), ader ); + } + for(unsigned j=0; j<3; ++j) { + for(unsigned k=0; k<3; ++k) resid->addDerivative( nargs + 3*getNumberOfAtoms() + 3*j + k, tvir(j,k) ); + } } } -void PCAVars::calculateNumericalDerivatives( ActionWithValue* a ){ - if( getNumberOfArguments()>0 ){ - ActionWithArguments::calculateNumericalDerivatives( a ); +void PCAVars::calculateNumericalDerivatives( ActionWithValue* a ) { + if( getNumberOfArguments()>0 ) { + ActionWithArguments::calculateNumericalDerivatives( a ); } - if( getNumberOfAtoms()>0 ){ - Matrix<double> save_derivatives( getNumberOfComponents(), getNumberOfArguments() ); - for(unsigned j=0;j<getNumberOfComponents();++j){ - for(unsigned i=0;i<getNumberOfArguments();++i) save_derivatives(j,i)=getPntrToComponent(j)->getDerivative(i); - } - calculateAtomicNumericalDerivatives( a, getNumberOfArguments() ); - for(unsigned j=0;j<getNumberOfComponents();++j){ - for(unsigned i=0;i<getNumberOfArguments();++i) getPntrToComponent(j)->addDerivative( i, save_derivatives(j,i) ); - } + if( getNumberOfAtoms()>0 ) { + Matrix<double> save_derivatives( getNumberOfComponents(), getNumberOfArguments() ); + for(unsigned j=0; j<getNumberOfComponents(); ++j) { + for(unsigned i=0; i<getNumberOfArguments(); ++i) save_derivatives(j,i)=getPntrToComponent(j)->getDerivative(i); + } + calculateAtomicNumericalDerivatives( a, getNumberOfArguments() ); + for(unsigned j=0; j<getNumberOfComponents(); ++j) { + for(unsigned i=0; i<getNumberOfArguments(); ++i) getPntrToComponent(j)->addDerivative( i, save_derivatives(j,i) ); + } } -} +} -void PCAVars::apply(){ +void PCAVars::apply() { bool wasforced=false; forcesToApply.assign(forcesToApply.size(),0.0); - for(unsigned i=0;i<getNumberOfComponents();++i){ - if( getPntrToComponent(i)->applyForce( forces ) ){ - wasforced=true; - for(unsigned i=0;i<forces.size();++i) forcesToApply[i]+=forces[i]; - } + for(unsigned i=0; i<getNumberOfComponents(); ++i) { + if( getPntrToComponent(i)->applyForce( forces ) ) { + wasforced=true; + for(unsigned i=0; i<forces.size(); ++i) forcesToApply[i]+=forces[i]; + } } - if( wasforced ){ - addForcesOnArguments( forcesToApply ); - if( getNumberOfAtoms()>0 ) setForcesOnAtoms( forcesToApply, getNumberOfArguments() ); + if( wasforced ) { + addForcesOnArguments( forcesToApply ); + if( getNumberOfAtoms()>0 ) setForcesOnAtoms( forcesToApply, getNumberOfArguments() ); } } diff --git a/src/mapping/Path.cpp b/src/mapping/Path.cpp index 7928ff3a2..37db777d2 100644 --- a/src/mapping/Path.cpp +++ b/src/mapping/Path.cpp @@ -24,14 +24,14 @@ //+PLUMEDOC COLVAR PATH /* -Path collective variables with a more flexible framework for the distance metric being used. +Path collective variables with a more flexible framework for the distance metric being used. The Path Collective Variables developed by Branduardi and co-workers \cite brand07 allow one to compute the progress along a high-dimensional path and the distance from the high-dimensional path. The progress along the path (s) is computed using: \f[ -s = \frac{ \sum_{i=1}^N i \exp( -\lambda R[X - X_i] ) }{ \sum_{i=1}^N \exp( -\lambda R[X - X_i] ) } +s = \frac{ \sum_{i=1}^N i \exp( -\lambda R[X - X_i] ) }{ \sum_{i=1}^N \exp( -\lambda R[X - X_i] ) } \f] while the distance from the path (z) is measured using: @@ -44,7 +44,7 @@ In these expressions \f$N\f$ high-dimensional frames (\f$X_i\f$) are used to des space. The two expressions above are then functions of the distances from each of the high-dimensional frames \f$R[X - X_i]\f$. Within PLUMED there are multiple ways to define the distance from a high-dimensional configuration. You could calculate the RMSD distance or you could calculate the ammount by which a set of collective variables change. As such this implementation -of the path cv allows one to use all the difference distance metrics that are discussed in \ref dists. This is as opposed to +of the path cv allows one to use all the difference distance metrics that are discussed in \ref dists. This is as opposed to the alternative implementation of path (\ref PATHMSD) which is a bit faster but which only allows one to use the RMSD distance. The \f$s\f$ and \f$z\f$ variables are calculated using the above formulas by default. However, there is an alternative method @@ -54,14 +54,14 @@ geometry (as opposed to algebra, which is used in the equations above). In this \f[ s = i_2 + \textrm{sign}(i_2-i_1) \frac{ \sqrt{( \mathbf{v}_1\cdot\mathbf{v}_2 )^2 - |\mathbf{v}_3|^2(|\mathbf{v}_1|^2 - |\mathbf{v}_2|^2) } }{2|\mathbf{v}_3|^2} - \frac{\mathbf{v}_1\cdot\mathbf{v}_3 - |\mathbf{v}_3|^2}{2|\mathbf{v}_3|^2} -\f] +\f] -where \f$\mathbf{v}_1\f$ and \f$\mathbf{v}_3\f$ are the vectors connecting the current position to the closest and second closest node of the path, -respectfully and \f$i_1\f$ and \f$i_2\f$ are the projections of the closest and second closest frames of the path. \f$\mathbf{v}_2\f$, meanwhile, is the +where \f$\mathbf{v}_1\f$ and \f$\mathbf{v}_3\f$ are the vectors connecting the current position to the closest and second closest node of the path, +respectfully and \f$i_1\f$ and \f$i_2\f$ are the projections of the closest and second closest frames of the path. \f$\mathbf{v}_2\f$, meanwhile, is the vector connecting the closest frame to the second closest frame. The distance from the path, \f$z\f$ is calculated using: \f[ -z = \sqrt{ \left[ |\mathbf{v}_1|^2 - |\mathbf{v}_2| \left( \frac{ \sqrt{( \mathbf{v}_1\cdot\mathbf{v}_2 )^2 - |\mathbf{v}_3|^2(|\mathbf{v}_1|^2 - |\mathbf{v}_2|^2) } }{2|\mathbf{v}_3|^2} - \frac{\mathbf{v}_1\cdot\mathbf{v}_3 - |\mathbf{v}_3|^2}{2|\mathbf{v}_3|^2} \right) \right]^2 } +z = \sqrt{ \left[ |\mathbf{v}_1|^2 - |\mathbf{v}_2| \left( \frac{ \sqrt{( \mathbf{v}_1\cdot\mathbf{v}_2 )^2 - |\mathbf{v}_3|^2(|\mathbf{v}_1|^2 - |\mathbf{v}_2|^2) } }{2|\mathbf{v}_3|^2} - \frac{\mathbf{v}_1\cdot\mathbf{v}_3 - |\mathbf{v}_3|^2}{2|\mathbf{v}_3|^2} \right) \right]^2 } \f] The symbols here are as they were for \f$s\f$. If you would like to use these equations to calculate \f$s\f$ and \f$z\f$ then you should use the GPATH flag. @@ -71,26 +71,26 @@ The values of \f$s\f$ and \f$z\f$ can then be referenced using the gspath and gz In the example below the path is defined using RMSD distance from frames. The reference frames in the path are defined in the pdb file. In this frame -each configuration in the path is separated by a line containing just the word END. +each configuration in the path is separated by a line containing just the word END. -\verbatim -p1: PATH REFERENCE=file.pdb TYPE=OPTIMAL LAMBDA=500.0 +\verbatim +p1: PATH REFERENCE=file.pdb TYPE=OPTIMAL LAMBDA=500.0 PRINT ARG=p1.sss,p1.zzz STRIDE=1 FILE=colvar FMT=%8.4f \endverbatim In the example below the path is defined using the values of two torsional angles (t1 and t2). -In addition, the \f$s\f$ and \f$z\f$ are calculated using the geometric expressions described +In addition, the \f$s\f$ and \f$z\f$ are calculated using the geometric expressions described above rather than the alegebraic expressions that are used by default. \verbatim t1: TORSION ATOMS=5,7,9,15 t2: TORSION ATOMS=7,9,15,17 pp: PATH TYPE=EUCLIDEAN REFERENCE=epath.pdb GPATH NOSPATH NOZPATH -PRINT ARG=pp.* FILE=colvar +PRINT ARG=pp.* FILE=colvar \endverbatim Notice that the LAMBDA parameter is not required here as we are not calculating \f$s\f$ and \f$s\f$ -using the algebraic formulae defined earlier. The positions of the frames in the path are defined +using the algebraic formulae defined earlier. The positions of the frames in the path are defined in the file epath.pdb. An extract from this file looks as shown below. \verbatim @@ -102,16 +102,16 @@ REMARK ARG=t1,t2 t1=-3.96947 t2=3.61947 END \endverbatim -The remarks in this pdb file tell PLUMED the labels that are being used to define the position in the +The remarks in this pdb file tell PLUMED the labels that are being used to define the position in the high dimensional space and the values that these arguments have at each point on the path. -The following input instructs PLUMED to calculate the values of the path collective variables. The frames that make up this -path are defined in the file all.pdb and all distances are measured using the OPTIMAL metric that is discussed in the manual -page on \ref RMSD. +The following input instructs PLUMED to calculate the values of the path collective variables. The frames that make up this +path are defined in the file all.pdb and all distances are measured using the OPTIMAL metric that is discussed in the manual +page on \ref RMSD. \verbatim p2: PATH REFERENCE=all.pdb LAMBDA=69087 -PRINT ARG=p2.spath,p2.zpath STRIDE=1 FILE=colvar +PRINT ARG=p2.spath,p2.zpath STRIDE=1 FILE=colvar \endverbatim If you wish to use collective variable values in the definition of your path you would use an input file with something like this: @@ -120,19 +120,19 @@ If you wish to use collective variable values in the definition of your path you d1: DISTANCE ATOMS=1,2 d2: DISTANCE ATOMS=3,4a p2: PATH REFERENCE=mypath.pdb LAMBDA=2 TYPE=EUCLIDEAN -PRINT ARG=p2.spath,p2.zpath STRIDE=1 FILE=colvar +PRINT ARG=p2.spath,p2.zpath STRIDE=1 FILE=colvar \endverbatim The corresponding pdb file containing the definitions of the frames in the path would then look like this: \verbatim DESCRIPTION: a defintiion of a PATH -REMARK TYPE=EUCLIDEAN -REMARK ARG=d1,d2 +REMARK TYPE=EUCLIDEAN +REMARK ARG=d1,d2 REMARK d1=1.0 d2=1.0 END REMARK TYPE=EUCLIDEAN -REMARK ARG=d1,d2 +REMARK ARG=d1,d2 REMARK d1=2.0 d2=2.0 END \endverbatim @@ -144,7 +144,7 @@ of the system and the reference configurations together with the values that the //+ENDPLUMEDOC namespace PLMD { -namespace mapping{ +namespace mapping { class Path : public PathBase { public: @@ -154,27 +154,27 @@ public: PLUMED_REGISTER_ACTION(Path,"PATH") -void Path::registerKeywords( Keywords& keys ){ +void Path::registerKeywords( Keywords& keys ) { PathBase::registerKeywords( keys ); keys.remove("PROPERTY"); keys.addFlag("NOSPATH",false,"do not calculate the spath position"); keys.remove("LOWMEM"); keys.use("GPATH"); } Path::Path(const ActionOptions& ao): -Action(ao), -PathBase(ao) + Action(ao), + PathBase(ao) { - setLowMemOption( true ); + setLowMemOption( true ); bool nos; parseFlag("NOSPATH",nos); std::string empty; - if(!nos){ - if( getPropertyIndex("spath")!=0 || getNumberOfProperties()>1 ){ - error("paths only work when there is a single property called sss being calculated"); - } - if( getLambda()==0 ) error("you must set LAMBDA parameter in order to calculate spath position. Use LAMBDA/NOSPATH keyword"); - empty="LABEL=spath"; - addVessel("SPATH",empty,0); + if(!nos) { + if( getPropertyIndex("spath")!=0 || getNumberOfProperties()>1 ) { + error("paths only work when there is a single property called sss being calculated"); + } + if( getLambda()==0 ) error("you must set LAMBDA parameter in order to calculate spath position. Use LAMBDA/NOSPATH keyword"); + empty="LABEL=spath"; + addVessel("SPATH",empty,0); } readVesselKeywords(); checkRead(); diff --git a/src/mapping/PathBase.cpp b/src/mapping/PathBase.cpp index 25c2862f9..af50f0375 100644 --- a/src/mapping/PathBase.cpp +++ b/src/mapping/PathBase.cpp @@ -23,41 +23,41 @@ #include "tools/SwitchingFunction.h" namespace PLMD { -namespace mapping{ +namespace mapping { -void PathBase::registerKeywords( Keywords& keys ){ - Mapping::registerKeywords( keys ); +void PathBase::registerKeywords( Keywords& keys ) { + Mapping::registerKeywords( keys ); keys.add("compulsory","LAMBDA","0","the value of the lambda parameter for paths"); keys.addFlag("NOZPATH",false,"do not calculate the zpath position"); } PathBase::PathBase(const ActionOptions& ao): -Action(ao), -Mapping(ao) + Action(ao), + Mapping(ao) { weightHasDerivatives=true; bool noz; parseFlag("NOZPATH",noz); parse("LAMBDA",lambda); // Create the list of tasks - for(unsigned i=0;i<getNumberOfReferencePoints();++i) addTaskToList( i ); - // And activate them all + for(unsigned i=0; i<getNumberOfReferencePoints(); ++i) addTaskToList( i ); + // And activate them all deactivateAllTasks(); - for(unsigned i=0;i<getFullNumberOfTasks();++i) taskFlags[i]=1; + for(unsigned i=0; i<getFullNumberOfTasks(); ++i) taskFlags[i]=1; lockContributors(); std::string empty="LABEL=zpath"; - if(!noz){ - if( lambda==0 ) error("you must set LAMDBA value in order to calculate ZPATH coordinate. Use LAMBDA/NOZPATH keyword"); - addVessel("ZPATH",empty,0); + if(!noz) { + if( lambda==0 ) error("you must set LAMDBA value in order to calculate ZPATH coordinate. Use LAMBDA/NOZPATH keyword"); + addVessel("ZPATH",empty,0); } } -double PathBase::getLambda(){ +double PathBase::getLambda() { return lambda; } -void PathBase::calculate(){ +void PathBase::calculate() { // Loop over all frames is now performed by ActionWithVessel runAllTasks(); } @@ -74,9 +74,9 @@ void PathBase::performTask( const unsigned& task_index, const unsigned& current, } double PathBase::transformHD( const double& dist, double& df ) const { - if( lambda==0 ){ df=1; return dist; } + if( lambda==0 ) { df=1; return dist; } double val = exp( -dist*lambda ); - df = -lambda*val; + df = -lambda*val; return val; } diff --git a/src/mapping/PathBase.h b/src/mapping/PathBase.h index 24975e24e..ab98922f6 100644 --- a/src/mapping/PathBase.h +++ b/src/mapping/PathBase.h @@ -25,7 +25,7 @@ #include "Mapping.h" namespace PLMD { -namespace mapping{ +namespace mapping { class PathBase : public Mapping { private: @@ -35,7 +35,7 @@ public: explicit PathBase(const ActionOptions&); double getLambda(); void calculate(); - void performTask( const unsigned& , const unsigned& , MultiValue& ) const ; + void performTask( const unsigned&, const unsigned&, MultiValue& ) const ; double transformHD( const double& dist, double& df ) const ; }; diff --git a/src/mapping/PathReparameterization.cpp b/src/mapping/PathReparameterization.cpp index a01940de3..df5169dd5 100644 --- a/src/mapping/PathReparameterization.cpp +++ b/src/mapping/PathReparameterization.cpp @@ -24,109 +24,109 @@ namespace PLMD { namespace mapping { -PathReparameterization::PathReparameterization( const Pbc& ipbc, const std::vector<Value*>& iargs, std::vector<ReferenceConfiguration*>& pp ): -mydpack( 1, pp[0]->getNumberOfReferenceArguments() + 3*pp[0]->getNumberOfReferencePositions() + 9 ), -mypack( pp[0]->getNumberOfReferenceArguments(), pp[0]->getNumberOfReferencePositions(), mydpack ), -mypath(pp), -pbc(ipbc), -args(iargs), -mydir(ReferenceConfigurationOptions("DIRECTION")), -len(pp.size()), -sumlen(pp.size()), -sfrac(pp.size()), -MAXCYCLES(100) +PathReparameterization::PathReparameterization( const Pbc& ipbc, const std::vector<Value*>& iargs, std::vector<ReferenceConfiguration*>& pp ): + mydpack( 1, pp[0]->getNumberOfReferenceArguments() + 3*pp[0]->getNumberOfReferencePositions() + 9 ), + mypack( pp[0]->getNumberOfReferenceArguments(), pp[0]->getNumberOfReferencePositions(), mydpack ), + mypath(pp), + pbc(ipbc), + args(iargs), + mydir(ReferenceConfigurationOptions("DIRECTION")), + len(pp.size()), + sumlen(pp.size()), + sfrac(pp.size()), + MAXCYCLES(100) { - mydir.setNamesAndAtomNumbers( pp[0]->getAbsoluteIndexes(), pp[0]->getArgumentNames() ); + mydir.setNamesAndAtomNumbers( pp[0]->getAbsoluteIndexes(), pp[0]->getArgumentNames() ); mydir.zeroDirection(); pp[0]->setupPCAStorage( mypack ); } bool PathReparameterization::loopEnd( const int& index, const int& end, const int& inc ) const { if( inc>0 && index<end ) return false; else if( inc<0 && index>end ) return false; - return true; + return true; } -void PathReparameterization::calcCurrentPathSpacings( const int& istart, const int& iend ){ +void PathReparameterization::calcCurrentPathSpacings( const int& istart, const int& iend ) { plumed_dbg_assert( istart<len.size() && iend<len.size() ); len[istart] = sumlen[istart]=0; //printf("HELLO PATH SPACINGS ARE CURRENTLY \n"); // Get the spacings given we can go forward and backwards - int incr=1; if( istart>iend ){ incr=-1; } + int incr=1; if( istart>iend ) { incr=-1; } - for(int i=istart+incr;loopEnd(i,iend+incr,incr)==false;i+=incr){ - len[i] = mypath[i-incr]->calc( mypath[i]->getReferencePositions(), pbc, args, mypath[i]->getReferenceArguments(), mypack, false ); - sumlen[i] = sumlen[i-incr] + len[i]; - //printf("FRAME %d TO FRAME %d EQUALS %f : %f \n",i-incr,i,len[i],sumlen[i] ); + for(int i=istart+incr; loopEnd(i,iend+incr,incr)==false; i+=incr) { + len[i] = mypath[i-incr]->calc( mypath[i]->getReferencePositions(), pbc, args, mypath[i]->getReferenceArguments(), mypack, false ); + sumlen[i] = sumlen[i-incr] + len[i]; + //printf("FRAME %d TO FRAME %d EQUALS %f : %f \n",i-incr,i,len[i],sumlen[i] ); } } -void PathReparameterization::reparameterizePart( const int& istart, const int& iend, const double& target, const double& TOL ){ +void PathReparameterization::reparameterizePart( const int& istart, const int& iend, const double& target, const double& TOL ) { calcCurrentPathSpacings( istart, iend ); unsigned cfin; // If a target separation is set we fix where we want the nodes - int incr=1; if( istart>iend ){ incr=-1; } - - if( target>0 ){ - if( iend>istart ){ - for(unsigned i=istart;i<iend+1;++i) sfrac[i] = target*(i-istart); - } else { - for(int i=istart-1;i>iend-1;--i) sfrac[i]=target*(istart-i); - } - cfin = iend+incr; + int incr=1; if( istart>iend ) { incr=-1; } + + if( target>0 ) { + if( iend>istart ) { + for(unsigned i=istart; i<iend+1; ++i) sfrac[i] = target*(i-istart); + } else { + for(int i=istart-1; i>iend-1; --i) sfrac[i]=target*(istart-i); + } + cfin = iend+incr; } else { - cfin = iend; + cfin = iend; } std::vector<Direction> newpath; - for(unsigned i=0;i<mypath.size();++i){ - newpath.push_back( Direction(ReferenceConfigurationOptions("DIRECTION")) ); - newpath[i].setNamesAndAtomNumbers( mypath[i]->getAbsoluteIndexes(), mypath[i]->getArgumentNames() ); + for(unsigned i=0; i<mypath.size(); ++i) { + newpath.push_back( Direction(ReferenceConfigurationOptions("DIRECTION")) ); + newpath[i].setNamesAndAtomNumbers( mypath[i]->getAbsoluteIndexes(), mypath[i]->getArgumentNames() ); } double prevsum=0.; - for(unsigned iter=0;iter<MAXCYCLES;++iter){ - if( fabs(sumlen[iend] - prevsum)<=TOL ) break ; - prevsum = sumlen[iend]; - // If no target is set we redistribute length - if( target<0 ){ - plumed_assert( istart<iend ); - double dr = sumlen[iend] / static_cast<double>( iend - istart ); - for(unsigned i=istart;i<iend;++i) sfrac[i] = dr*(i-istart); - } - - // Now compute positions of new nodes in path - for(int i=istart+incr;loopEnd(i,cfin,incr)==false;i+=incr){ - int k = istart; - while( !((sumlen[k] < sfrac[i]) && (sumlen[k+incr]>=sfrac[i])) ){ - k+=incr; - if( cfin==iend && k>= iend+1 ) plumed_merror("path reparameterization error"); - else if( cfin==(iend+1) && k>=iend ){ k=iend-1; break; } - else if( cfin==(iend-1) && k<=iend ){ k=iend+1; break; } - } - double dr = (sfrac[i]-sumlen[k])/len[k+incr]; - // Calculate the displacement between the appropriate points - // double dd = mypath[k]->calc( mypath[k+incr]->getReferencePositions(), pbc, args, mypath[k+incr]->getReferenceArguments(), mypack, true ); - // Copy the reference configuration from the configuration to a tempory direction - newpath[i].setDirection( mypath[k]->getReferencePositions(), mypath[k]->getReferenceArguments() ); - // Get the displacement of the path - mypath[k]->extractDisplacementVector( mypath[k+incr]->getReferencePositions(), args, mypath[k+incr]->getReferenceArguments(), false, false, mydir ); - // Set our direction equal to the displacement - // mydir.setDirection( mypack ); - // Shift the reference configuration by this ammount - newpath[i].displaceReferenceConfiguration( dr, mydir ); - } - - // Copy the positions of the new path to the new paths - for(int i=istart+incr;loopEnd(i,cfin,incr)==false;i+=incr){ - mypath[i]->setReferenceConfig( newpath[i].getReferencePositions(), newpath[i].getReferenceArguments(), mypath[i]->getReferenceMetric() ); - } - - // Recompute the separations between frames - calcCurrentPathSpacings( istart, iend ); + for(unsigned iter=0; iter<MAXCYCLES; ++iter) { + if( fabs(sumlen[iend] - prevsum)<=TOL ) break ; + prevsum = sumlen[iend]; + // If no target is set we redistribute length + if( target<0 ) { + plumed_assert( istart<iend ); + double dr = sumlen[iend] / static_cast<double>( iend - istart ); + for(unsigned i=istart; i<iend; ++i) sfrac[i] = dr*(i-istart); + } + + // Now compute positions of new nodes in path + for(int i=istart+incr; loopEnd(i,cfin,incr)==false; i+=incr) { + int k = istart; + while( !((sumlen[k] < sfrac[i]) && (sumlen[k+incr]>=sfrac[i])) ) { + k+=incr; + if( cfin==iend && k>= iend+1 ) plumed_merror("path reparameterization error"); + else if( cfin==(iend+1) && k>=iend ) { k=iend-1; break; } + else if( cfin==(iend-1) && k<=iend ) { k=iend+1; break; } + } + double dr = (sfrac[i]-sumlen[k])/len[k+incr]; + // Calculate the displacement between the appropriate points + // double dd = mypath[k]->calc( mypath[k+incr]->getReferencePositions(), pbc, args, mypath[k+incr]->getReferenceArguments(), mypack, true ); + // Copy the reference configuration from the configuration to a tempory direction + newpath[i].setDirection( mypath[k]->getReferencePositions(), mypath[k]->getReferenceArguments() ); + // Get the displacement of the path + mypath[k]->extractDisplacementVector( mypath[k+incr]->getReferencePositions(), args, mypath[k+incr]->getReferenceArguments(), false, false, mydir ); + // Set our direction equal to the displacement + // mydir.setDirection( mypack ); + // Shift the reference configuration by this ammount + newpath[i].displaceReferenceConfiguration( dr, mydir ); + } + + // Copy the positions of the new path to the new paths + for(int i=istart+incr; loopEnd(i,cfin,incr)==false; i+=incr) { + mypath[i]->setReferenceConfig( newpath[i].getReferencePositions(), newpath[i].getReferenceArguments(), mypath[i]->getReferenceMetric() ); + } + + // Recompute the separations between frames + calcCurrentPathSpacings( istart, iend ); } } -void PathReparameterization::reparameterize( const int& ifix1, const int& ifix2, const double& TOL ){ +void PathReparameterization::reparameterize( const int& ifix1, const int& ifix2, const double& TOL ) { plumed_dbg_assert( ifix1<ifix2 ); // First reparameterize the part between the fixed frames reparameterizePart( ifix1, ifix2, -1.0, TOL ); @@ -137,7 +137,7 @@ void PathReparameterization::reparameterize( const int& ifix1, const int& ifix2, // And reparameterize the begining and end of the path if( ifix1>0 ) reparameterizePart( ifix1, 0, target, TOL ); if( ifix2<(mypath.size()-1) ) reparameterizePart( ifix2, mypath.size()-1, target, TOL ); -// calcCurrentPathSpacings( 0, mypath.size()-1 ); +// calcCurrentPathSpacings( 0, mypath.size()-1 ); } } diff --git a/src/mapping/PathReparameterization.h b/src/mapping/PathReparameterization.h index dfbf61e62..9a5a6c318 100644 --- a/src/mapping/PathReparameterization.h +++ b/src/mapping/PathReparameterization.h @@ -55,7 +55,7 @@ private: /// Reparameterize the frames of the path between istart and iend and make the spacing equal to target void reparameterizePart( const int& istart, const int& iend, const double& target, const double& TOL ); public: - PathReparameterization( const Pbc& ipbc, const std::vector<Value*>& iargs, std::vector<ReferenceConfiguration*>& pp ); + PathReparameterization( const Pbc& ipbc, const std::vector<Value*>& iargs, std::vector<ReferenceConfiguration*>& pp ); /// Reparameterize the frames of the path between istart and iend so as to make the spacing constant void reparameterize( const int& istart, const int& iend, const double& TOL ); }; diff --git a/src/mapping/PathTools.cpp b/src/mapping/PathTools.cpp index a4884b4fa..abb9f7c5c 100644 --- a/src/mapping/PathTools.cpp +++ b/src/mapping/PathTools.cpp @@ -35,30 +35,30 @@ using namespace std; namespace PLMD { -namespace mapping{ +namespace mapping { //+PLUMEDOC TOOLS pathtools /* pathtools can be used to construct paths from pdb data The path CVs in PLUMED are curvilinear coordinates through a high dimensional vector space. -Enhanced sampling calculations are ofen run using the progress along the paths and the distance from the path as CVs +Enhanced sampling calculations are ofen run using the progress along the paths and the distance from the path as CVs as this provides a convenient way of defining a reaction coordinate for a complicated process. This method is explained in the documentation for \ref PATH. The path itself is an ordered set of equally-spaced, high-dimensional frames the way in which these frames should be constructed will depend on the problem in hand. In other words, you will need to understand the reaction -you wish to study in order to select a sensible set of frames to use in your path CV. This tool provides two +you wish to study in order to select a sensible set of frames to use in your path CV. This tool provides two methods that may be useful when it comes to constructing paths; namely: - A tool that takes in an initial guess path in which the frames are not equally spaced. This tool adjusts the positions of the frames in order to make them equally spaced so that they can be used as the basis for a path CV. -- A tool that takes two frames as input and that allows you to return a linear path connecting these two frames. The -output from this method may be useful as an initial guess path. It is arguable that a linear path rather defeats the +- A tool that takes two frames as input and that allows you to return a linear path connecting these two frames. The +output from this method may be useful as an initial guess path. It is arguable that a linear path rather defeats the purpose of the path CV method, however, as the whole purpose is to be able to define non-linear paths. -Notice that you can use these two methods and take advantage of all the ways of measuring \ref dists that are available within +Notice that you can use these two methods and take advantage of all the ways of measuring \ref dists that are available within PLUMED. The way you do this with each of these tools described above is explained in the example below. \par Examples @@ -75,12 +75,12 @@ The example below shows how can create an initial linear path connecting the two end.pdb. In this case the path output to path.pdb will consist of 6 frames: the initial and final frames that were contained in start.pdb and end.pdb as well as four equally spaced frames along the vector connecting start.pdb to end.pdb. - + \verbatim plumed pathtools --start start.pdb --end end.pdb --nframes 4 --metric OPTIMAL --out path.pdb \endverbatim -Often the idea with path cvs is to create a path connecting some initial state A to some final state B. You would +Often the idea with path cvs is to create a path connecting some initial state A to some final state B. You would in this case have representative configurations from your A and B states defined in the input files to pathtools that we have called start.pdb and end.pdb in the example above. Furthermore, it may be useful to have a few frames before your start frame and after your end frame. You can use path tools to create these extended paths as shown below. @@ -93,7 +93,7 @@ plumed pathtools --start start.pdb --end end.pdb --nframes 4 --metric OPTIMAL -- \endverbatim Notice also that when you reparameterise paths you must choose two frames to fix. Generally you chose to fix the states -that are representative of your states A and B. By default pathtools will fix the first and last frames. You can, however, +that are representative of your states A and B. By default pathtools will fix the first and last frames. You can, however, change the states to fix by taking advantage of the fixed flag as shown below. \verbatim @@ -104,20 +104,20 @@ plumed pathtools --path inpath.pdb --metric EUCLIDEAN --out outpath.pdb --fixed //+ENDPLUMEDOC class PathTools : -public CLTool + public CLTool { public: static void registerKeywords( Keywords& keys ); explicit PathTools(const CLToolOptions& co ); int main(FILE* in, FILE*out,Communicator& pc); - string description()const{ + string description()const { return "print out a description of the keywords for an action in html"; } }; PLUMED_REGISTER_CLTOOL(PathTools,"pathtools") -void PathTools::registerKeywords( Keywords& keys ){ +void PathTools::registerKeywords( Keywords& keys ) { CLTool::registerKeywords( keys ); keys.add("atoms","--start","a pdb file that contains the structure for the initial frame of your path"); keys.add("atoms","--end","a pdb file that contains the structure for the final frame of your path"); @@ -133,160 +133,160 @@ void PathTools::registerKeywords( Keywords& keys ){ } PathTools::PathTools(const CLToolOptions& co ): -CLTool(co) + CLTool(co) { inputdata=commandline; } -int PathTools::main(FILE* in, FILE*out,Communicator& pc){ - - std::string mtype; parse("--metric",mtype); - std::string ifilename; parse("--path",ifilename); - std::string ofmt; parse("--arg-fmt",ofmt); - std::string ofilename; parse("--out",ofilename); - if( ifilename.length()>0 ){ - fprintf(out,"Reparameterising path in file named %s so that all frames are equally spaced \n",ifilename.c_str() ); - FILE* fp=fopen(ifilename.c_str(),"r"); - bool do_read=true; std::vector<ReferenceConfiguration*> frames; - while (do_read) { - PDB mypdb; - // Read the pdb file - do_read=mypdb.readFromFilepointer(fp,false,0.1); - if( do_read ){ - ReferenceConfiguration* mymsd=metricRegister().create<ReferenceConfiguration>( mtype, mypdb ); - frames.push_back( mymsd ); mymsd->checkRead(); - } - } - std::vector<unsigned> fixed; parseVector("--fixed",fixed); - if( fixed.size()==1 ){ - if( fixed[0]!=0 ) error("input to --fixed should be two integers"); - fixed.resize(2); fixed[0]=0; fixed[1]=frames.size()-1; - } else if( fixed.size()==2 ){ - if( fixed[0]<0 || fixed[1]<0 || fixed[0]>(frames.size()-1) || fixed[1]>(frames.size()-1) ){ - error("input to --fixed should be two numbers between 0 and the number of frames-1"); - } - } else { - error("input to --fixed should be two integers"); - } - std::vector<AtomNumber> atoms; std::vector<std::string> arg_names; - for(unsigned i=0;i<frames.size();++i){ - frames[i]->getAtomRequests( atoms); - frames[i]->getArgumentRequests( arg_names ); - } - // Generate stuff to reparameterize - Pbc fake_pbc; std::vector<Value*> vals; - for(unsigned i=0;i<frames[0]->getNumberOfReferenceArguments();++i){ - vals.push_back(new Value()); vals[vals.size()-1]->setNotPeriodic(); - } - // And reparameterize - PathReparameterization myparam( fake_pbc, vals, frames ); - // And make all points equally spaced - double tol; parse("--tolerance",tol); myparam.reparameterize( fixed[0], fixed[1], tol ); - - // Ouput data on spacings - double mean=0; - MultiValue myvpack( 1, frames[0]->getNumberOfReferenceArguments() + 3*frames[0]->getNumberOfReferencePositions() + 9 ); - ReferenceValuePack mypack( frames[0]->getNumberOfReferenceArguments(), frames[0]->getNumberOfReferencePositions(), myvpack ); - for(unsigned i=1;i<frames.size();++i){ - double len = frames[i]->calc( frames[i-1]->getReferencePositions(), fake_pbc, vals, frames[i-1]->getReferenceArguments(), mypack, false ); - printf("FINAL DISTANCE BETWEEN FRAME %u AND %u IS %f \n",i-1,i,len ); - mean+=len; - } - printf("SUGGESTED LAMBDA PARAMETER IS THUS %f \n",2.3/mean/static_cast<double>( frames.size()-1 ) ); - - // Delete all the frames - OFile ofile; ofile.open(ofilename); - for(unsigned i=0;i<frames.size();++i){ frames[i]->print( ofile, ofmt, 10. ); delete frames[i]; } - // Delete the vals as we don't need them - for(unsigned i=0;i<vals.size();++i) delete vals[i]; - // Return as we are done - ofile.close(); return 0; - } - - // Read initial frame - std::string istart; parse("--start",istart); FILE* fp2=fopen(istart.c_str(),"r"); PDB mystartpdb; - if( istart.length()==0 ) error("input is missing use --istart + --iend or --path"); - if( !mystartpdb.readFromFilepointer(fp2,false,0.1) ) error("could not read fila " + istart); - ReferenceConfiguration* sframe=metricRegister().create<ReferenceConfiguration>( mtype, mystartpdb ); - fclose(fp2); - - // Read final frame - std::string iend; parse("--end",iend); FILE* fp1=fopen(iend.c_str(),"r"); PDB myendpdb; - if( iend.length()==0 ) error("input is missing using --istart + --iend or --path"); - if( !myendpdb.readFromFilepointer(fp1,false,0.1) ) error("could not read fila " + iend); - ReferenceConfiguration* eframe=metricRegister().create<ReferenceConfiguration>( mtype, myendpdb ); - fclose(fp1); - - // Get atoms and arg requests - std::vector<AtomNumber> atoms; std::vector<std::string> arg_names; - sframe->getAtomRequests( atoms); eframe->getAtomRequests( atoms); - sframe->getArgumentRequests( arg_names ); eframe->getArgumentRequests( arg_names ); - - // Now read in the rest of the instructions - unsigned nbefore, nbetween, nafter; - parse("--nframes-before-start",nbefore); parse("--nframes",nbetween); parse("--nframes-after-end",nafter); - nbetween++; - fprintf(out,"Generating linear path connecting structure in file named %s to structure in file named %s \n",istart.c_str(),iend.c_str() ); - fprintf(out,"A path consisting of %u equally-spaced frames before the initial structure, %u frames between the intial and final structures " - "and %u frames after the final structure will be created \n",nbefore,nbetween,nafter); - - // Create a vector of arguments to use for calculating displacements - Pbc fpbc; std::vector<Value*> args; - for(unsigned i=0;i<eframe->getNumberOfReferenceArguments();++i){ - args.push_back(new Value()); args[args.size()-1]->setNotPeriodic(); - } - - // Calculate the distance between the start and the end - MultiValue myvpack( 1, sframe->getNumberOfReferenceArguments() + 3*sframe->getNumberOfReferencePositions() + 9); - ReferenceValuePack mypack( sframe->getNumberOfReferenceArguments(), sframe->getNumberOfReferencePositions(), myvpack ); - double pathlen = sframe->calc( eframe->getReferencePositions(), fpbc, args, eframe->getReferenceArguments(), mypack, false ); - // And the spacing between frames - double delr = 1.0 / static_cast<double>( nbetween ); - // Calculate the vector connecting the start to the end - Direction mydir(ReferenceConfigurationOptions("DIRECTION")); sframe->setupPCAStorage( mypack ); - mydir.setNamesAndAtomNumbers( sframe->getAbsoluteIndexes(), sframe->getArgumentNames() ); mydir.zeroDirection(); - sframe->extractDisplacementVector( eframe->getReferencePositions(), args, eframe->getReferenceArguments(), false, false, mydir ); - - - // Now create frames - std::vector<ReferenceConfiguration*> final_path; - Direction pos(ReferenceConfigurationOptions("DIRECTION")); - pos.setNamesAndAtomNumbers( sframe->getAbsoluteIndexes(), sframe->getArgumentNames() ); - for(int i=0;i<nbefore;++i){ +int PathTools::main(FILE* in, FILE*out,Communicator& pc) { + + std::string mtype; parse("--metric",mtype); + std::string ifilename; parse("--path",ifilename); + std::string ofmt; parse("--arg-fmt",ofmt); + std::string ofilename; parse("--out",ofilename); + if( ifilename.length()>0 ) { + fprintf(out,"Reparameterising path in file named %s so that all frames are equally spaced \n",ifilename.c_str() ); + FILE* fp=fopen(ifilename.c_str(),"r"); + bool do_read=true; std::vector<ReferenceConfiguration*> frames; + while (do_read) { + PDB mypdb; + // Read the pdb file + do_read=mypdb.readFromFilepointer(fp,false,0.1); + if( do_read ) { + ReferenceConfiguration* mymsd=metricRegister().create<ReferenceConfiguration>( mtype, mypdb ); + frames.push_back( mymsd ); mymsd->checkRead(); + } + } + std::vector<unsigned> fixed; parseVector("--fixed",fixed); + if( fixed.size()==1 ) { + if( fixed[0]!=0 ) error("input to --fixed should be two integers"); + fixed.resize(2); fixed[0]=0; fixed[1]=frames.size()-1; + } else if( fixed.size()==2 ) { + if( fixed[0]<0 || fixed[1]<0 || fixed[0]>(frames.size()-1) || fixed[1]>(frames.size()-1) ) { + error("input to --fixed should be two numbers between 0 and the number of frames-1"); + } + } else { + error("input to --fixed should be two integers"); + } + std::vector<AtomNumber> atoms; std::vector<std::string> arg_names; + for(unsigned i=0; i<frames.size(); ++i) { + frames[i]->getAtomRequests( atoms); + frames[i]->getArgumentRequests( arg_names ); + } + // Generate stuff to reparameterize + Pbc fake_pbc; std::vector<Value*> vals; + for(unsigned i=0; i<frames[0]->getNumberOfReferenceArguments(); ++i) { + vals.push_back(new Value()); vals[vals.size()-1]->setNotPeriodic(); + } + // And reparameterize + PathReparameterization myparam( fake_pbc, vals, frames ); + // And make all points equally spaced + double tol; parse("--tolerance",tol); myparam.reparameterize( fixed[0], fixed[1], tol ); + + // Ouput data on spacings + double mean=0; + MultiValue myvpack( 1, frames[0]->getNumberOfReferenceArguments() + 3*frames[0]->getNumberOfReferencePositions() + 9 ); + ReferenceValuePack mypack( frames[0]->getNumberOfReferenceArguments(), frames[0]->getNumberOfReferencePositions(), myvpack ); + for(unsigned i=1; i<frames.size(); ++i) { + double len = frames[i]->calc( frames[i-1]->getReferencePositions(), fake_pbc, vals, frames[i-1]->getReferenceArguments(), mypack, false ); + printf("FINAL DISTANCE BETWEEN FRAME %u AND %u IS %f \n",i-1,i,len ); + mean+=len; + } + printf("SUGGESTED LAMBDA PARAMETER IS THUS %f \n",2.3/mean/static_cast<double>( frames.size()-1 ) ); + + // Delete all the frames + OFile ofile; ofile.open(ofilename); + for(unsigned i=0; i<frames.size(); ++i) { frames[i]->print( ofile, ofmt, 10. ); delete frames[i]; } + // Delete the vals as we don't need them + for(unsigned i=0; i<vals.size(); ++i) delete vals[i]; + // Return as we are done + ofile.close(); return 0; + } + +// Read initial frame + std::string istart; parse("--start",istart); FILE* fp2=fopen(istart.c_str(),"r"); PDB mystartpdb; + if( istart.length()==0 ) error("input is missing use --istart + --iend or --path"); + if( !mystartpdb.readFromFilepointer(fp2,false,0.1) ) error("could not read fila " + istart); + ReferenceConfiguration* sframe=metricRegister().create<ReferenceConfiguration>( mtype, mystartpdb ); + fclose(fp2); + +// Read final frame + std::string iend; parse("--end",iend); FILE* fp1=fopen(iend.c_str(),"r"); PDB myendpdb; + if( iend.length()==0 ) error("input is missing using --istart + --iend or --path"); + if( !myendpdb.readFromFilepointer(fp1,false,0.1) ) error("could not read fila " + iend); + ReferenceConfiguration* eframe=metricRegister().create<ReferenceConfiguration>( mtype, myendpdb ); + fclose(fp1); + +// Get atoms and arg requests + std::vector<AtomNumber> atoms; std::vector<std::string> arg_names; + sframe->getAtomRequests( atoms); eframe->getAtomRequests( atoms); + sframe->getArgumentRequests( arg_names ); eframe->getArgumentRequests( arg_names ); + +// Now read in the rest of the instructions + unsigned nbefore, nbetween, nafter; + parse("--nframes-before-start",nbefore); parse("--nframes",nbetween); parse("--nframes-after-end",nafter); + nbetween++; + fprintf(out,"Generating linear path connecting structure in file named %s to structure in file named %s \n",istart.c_str(),iend.c_str() ); + fprintf(out,"A path consisting of %u equally-spaced frames before the initial structure, %u frames between the intial and final structures " + "and %u frames after the final structure will be created \n",nbefore,nbetween,nafter); + +// Create a vector of arguments to use for calculating displacements + Pbc fpbc; std::vector<Value*> args; + for(unsigned i=0; i<eframe->getNumberOfReferenceArguments(); ++i) { + args.push_back(new Value()); args[args.size()-1]->setNotPeriodic(); + } + +// Calculate the distance between the start and the end + MultiValue myvpack( 1, sframe->getNumberOfReferenceArguments() + 3*sframe->getNumberOfReferencePositions() + 9); + ReferenceValuePack mypack( sframe->getNumberOfReferenceArguments(), sframe->getNumberOfReferencePositions(), myvpack ); + double pathlen = sframe->calc( eframe->getReferencePositions(), fpbc, args, eframe->getReferenceArguments(), mypack, false ); +// And the spacing between frames + double delr = 1.0 / static_cast<double>( nbetween ); +// Calculate the vector connecting the start to the end + Direction mydir(ReferenceConfigurationOptions("DIRECTION")); sframe->setupPCAStorage( mypack ); + mydir.setNamesAndAtomNumbers( sframe->getAbsoluteIndexes(), sframe->getArgumentNames() ); mydir.zeroDirection(); + sframe->extractDisplacementVector( eframe->getReferencePositions(), args, eframe->getReferenceArguments(), false, false, mydir ); + + +// Now create frames + std::vector<ReferenceConfiguration*> final_path; + Direction pos(ReferenceConfigurationOptions("DIRECTION")); + pos.setNamesAndAtomNumbers( sframe->getAbsoluteIndexes(), sframe->getArgumentNames() ); + for(int i=0; i<nbefore; ++i) { pos.setDirection( sframe->getReferencePositions(), sframe->getReferenceArguments() ); - pos.displaceReferenceConfiguration( -i*delr, mydir ); - final_path.push_back( metricRegister().create<ReferenceConfiguration>(mtype) ); + pos.displaceReferenceConfiguration( -i*delr, mydir ); + final_path.push_back( metricRegister().create<ReferenceConfiguration>(mtype) ); final_path[final_path.size()-1]->setNamesAndAtomNumbers( sframe->getAbsoluteIndexes(), sframe->getArgumentNames() ); final_path[final_path.size()-1]->setReferenceConfig( pos.getReferencePositions(), pos.getReferenceArguments(), sframe->getReferenceMetric() ); - } - for(unsigned i=1;i<nbetween;++i){ + } + for(unsigned i=1; i<nbetween; ++i) { pos.setDirection( sframe->getReferencePositions(), sframe->getReferenceArguments() ); pos.displaceReferenceConfiguration( i*delr, mydir ); - final_path.push_back( metricRegister().create<ReferenceConfiguration>(mtype) ); + final_path.push_back( metricRegister().create<ReferenceConfiguration>(mtype) ); final_path[final_path.size()-1]->setNamesAndAtomNumbers( sframe->getAbsoluteIndexes(), sframe->getArgumentNames() ); final_path[final_path.size()-1]->setReferenceConfig( pos.getReferencePositions(), pos.getReferenceArguments(), sframe->getReferenceMetric() ); - } - for(unsigned i=0;i<nafter;++i){ + } + for(unsigned i=0; i<nafter; ++i) { pos.setDirection( eframe->getReferencePositions(), eframe->getReferenceArguments() ); pos.displaceReferenceConfiguration( i*delr, mydir ); final_path.push_back( metricRegister().create<ReferenceConfiguration>(mtype) ); final_path[final_path.size()-1]->setNamesAndAtomNumbers( sframe->getAbsoluteIndexes(), sframe->getArgumentNames() ); final_path[final_path.size()-1]->setReferenceConfig( pos.getReferencePositions(), pos.getReferenceArguments(), sframe->getReferenceMetric() ); - } + } - double mean=0; printf("DISTANCE BETWEEN ORIGINAL FRAMES %f \n",pathlen); - for(unsigned i=1;i<final_path.size();++i){ + double mean=0; printf("DISTANCE BETWEEN ORIGINAL FRAMES %f \n",pathlen); + for(unsigned i=1; i<final_path.size(); ++i) { double len = final_path[i]->calc( final_path[i-1]->getReferencePositions(), fpbc, args, final_path[i-1]->getReferenceArguments(), mypack, false ); printf("FINAL DISTANCE BETWEEN FRAME %u AND %u IS %f \n",i-1,i,len ); mean+=len; - } - printf("SUGGESTED LAMBDA PARAMETER IS THUS %f \n",2.3/mean/static_cast<double>( final_path.size()-1 ) ); - - OFile ofile; ofile.open(ofilename); - for(unsigned i=0;i<final_path.size();++i){ final_path[i]->print( ofile, ofmt, 10. ); delete final_path[i]; } - // Delete the args as we don't need them anymore - for(unsigned i=0;i<args.size();++i) delete args[i]; - ofile.close(); delete sframe; delete eframe; return 0; + } + printf("SUGGESTED LAMBDA PARAMETER IS THUS %f \n",2.3/mean/static_cast<double>( final_path.size()-1 ) ); + + OFile ofile; ofile.open(ofilename); + for(unsigned i=0; i<final_path.size(); ++i) { final_path[i]->print( ofile, ofmt, 10. ); delete final_path[i]; } +// Delete the args as we don't need them anymore + for(unsigned i=0; i<args.size(); ++i) delete args[i]; + ofile.close(); delete sframe; delete eframe; return 0; } } // End of namespace diff --git a/src/mapping/PropertyMap.cpp b/src/mapping/PropertyMap.cpp index d24a46d28..9da32b47b 100644 --- a/src/mapping/PropertyMap.cpp +++ b/src/mapping/PropertyMap.cpp @@ -24,7 +24,7 @@ //+PLUMEDOC COLVAR GPROPERTYMAP /* -Property maps but with a more flexible framework for the distance metric being used. +Property maps but with a more flexible framework for the distance metric being used. This colvar calculates a property map using the formalism developed by Spiwork \cite Spiwok:2011ce. In essence if you have the value of some property, \f$X_i\f$, that it takes at a set of high-dimensional @@ -37,22 +37,22 @@ X=\frac{\sum_i X_i*\exp(-\lambda D_i(x))}{\sum_i \exp(-\lambda D_i(x))} Within PLUMED there are multiple ways to define the distance from a high-dimensional configuration, \f$D_i\f$. You could calculate the RMSD distance or you could calculate the ammount by which a set of collective variables change. As such this implementation -of the propertymap allows one to use all the different distance metric that are discussed in \ref dists. This is as opposed to +of the propertymap allows one to use all the different distance metric that are discussed in \ref dists. This is as opposed to the alternative implementation \ref PROPERTYMAP which is a bit faster but which only allows one to use the RMSD distance. \par Examples -The input shown below can be used to calculate the interpolated values of two properties called X and Y based on the values -that these properties take at a set of reference configurations and using the formula above. For this input the distances -between the reference configurations and the instantaneous configurations are calculated using the OPTIMAL metric that is +The input shown below can be used to calculate the interpolated values of two properties called X and Y based on the values +that these properties take at a set of reference configurations and using the formula above. For this input the distances +between the reference configurations and the instantaneous configurations are calculated using the OPTIMAL metric that is discussed at length in the manual pages on \ref RMSD. \verbatim p2: GPROPERTYMAP REFERENCE=allv.pdb PROPERTY=X,Y LAMBDA=69087 -PRINT ARG=p2.X,p2.Y,p2.zpath STRIDE=1 FILE=colvar +PRINT ARG=p2.X,p2.Y,p2.zpath STRIDE=1 FILE=colvar \endverbatim -The additional input file for this calculation, which contains the reference frames and the values of X and Y at these reference +The additional input file for this calculation, which contains the reference frames and the values of X and Y at these reference points has the following format. \verbatim @@ -93,7 +93,7 @@ END //+ENDPLUMEDOC namespace PLMD { -namespace mapping{ +namespace mapping { class PropertyMap : public PathBase { public: @@ -103,24 +103,24 @@ public: PLUMED_REGISTER_ACTION(PropertyMap,"GPROPERTYMAP") -void PropertyMap::registerKeywords( Keywords& keys ){ +void PropertyMap::registerKeywords( Keywords& keys ) { PathBase::registerKeywords( keys ); ActionWithValue::useCustomisableComponents( keys ); keys.addFlag("NOMAPPING",false,"do not calculate the position on the manifold"); } PropertyMap::PropertyMap(const ActionOptions& ao): -Action(ao), -PathBase(ao) + Action(ao), + PathBase(ao) { bool nos; parseFlag("NOMAPPING",nos); std::string empty; - if(!nos){ - for(unsigned i=0;i<getNumberOfProperties();++i){ - empty="LABEL="+getPropertyName(i); - addVessel( "SPATH", empty, 0 ); - } + if(!nos) { + for(unsigned i=0; i<getNumberOfProperties(); ++i) { + empty="LABEL="+getPropertyName(i); + addVessel( "SPATH", empty, 0 ); + } } readVesselKeywords(); checkRead(); diff --git a/src/mapping/SpathVessel.cpp b/src/mapping/SpathVessel.cpp index cb98602d5..23271e14f 100644 --- a/src/mapping/SpathVessel.cpp +++ b/src/mapping/SpathVessel.cpp @@ -42,35 +42,35 @@ public: PLUMED_REGISTER_VESSEL(SpathVessel,"SPATH") -void SpathVessel::registerKeywords( Keywords& keys ){ +void SpathVessel::registerKeywords( Keywords& keys ) { FunctionVessel::registerKeywords(keys); } -void SpathVessel::reserveKeyword( Keywords& keys ){ +void SpathVessel::reserveKeyword( Keywords& keys ) { keys.reserve("vessel","SPATH","docs should not appear"); keys.addOutputComponent("spath","SPATH","the position on the path"); } SpathVessel::SpathVessel( const vesselbase::VesselOptions& da ): -FunctionVessel(da), -foundoneclose(false) + FunctionVessel(da), + foundoneclose(false) { mymap=dynamic_cast<Mapping*>( getAction() ); plumed_massert( mymap, "SpathVessel can only be used with mappings"); // Retrieve the index of the property in the underlying mapping - mycoordnumber=mymap->getPropertyIndex( getLabel() ); - usetol=true; norm=true; + mycoordnumber=mymap->getPropertyIndex( getLabel() ); + usetol=true; norm=true; - for(unsigned i=0;i<mymap->getFullNumberOfTasks();++i){ - if( mymap->getTaskCode(i)!=mymap->getPositionInFullTaskList(i) ) error("mismatched tasks and codes"); + for(unsigned i=0; i<mymap->getFullNumberOfTasks(); ++i) { + if( mymap->getTaskCode(i)!=mymap->getPositionInFullTaskList(i) ) error("mismatched tasks and codes"); } } -std::string SpathVessel::value_descriptor(){ +std::string SpathVessel::value_descriptor() { return "the position on the path"; } -void SpathVessel::prepare(){ +void SpathVessel::prepare() { foundoneclose=false; } @@ -78,10 +78,10 @@ void SpathVessel::calculate( const unsigned& current, MultiValue& myvals, std::v double pp=mymap->getPropertyValue( current, mycoordnumber ), weight=myvals.get(0); if( weight<getTolerance() ) return; unsigned nderivatives=getFinalValue()->getNumberOfDerivatives(); - buffer[bufstart] += weight*pp; buffer[bufstart+1+nderivatives] += weight; - if( getAction()->derivativesAreRequired() ){ - myvals.chainRule( 0, 0, 1, 0, pp, bufstart, buffer ); - myvals.chainRule( 0, 1, 1, 0, 1.0, bufstart, buffer ); + buffer[bufstart] += weight*pp; buffer[bufstart+1+nderivatives] += weight; + if( getAction()->derivativesAreRequired() ) { + myvals.chainRule( 0, 0, 1, 0, pp, bufstart, buffer ); + myvals.chainRule( 0, 1, 1, 0, 1.0, bufstart, buffer ); } } diff --git a/src/mapping/TrigonometricPathVessel.cpp b/src/mapping/TrigonometricPathVessel.cpp index 920a792e8..adf049b70 100644 --- a/src/mapping/TrigonometricPathVessel.cpp +++ b/src/mapping/TrigonometricPathVessel.cpp @@ -27,193 +27,193 @@ namespace mapping { PLUMED_REGISTER_VESSEL(TrigonometricPathVessel,"GPATH") -void TrigonometricPathVessel::registerKeywords( Keywords& keys ){ +void TrigonometricPathVessel::registerKeywords( Keywords& keys ) { StoreDataVessel::registerKeywords(keys); } -void TrigonometricPathVessel::reserveKeyword( Keywords& keys ){ +void TrigonometricPathVessel::reserveKeyword( Keywords& keys ) { keys.reserve("vessel","GPATH","calculate the position on the path using trigonometry"); keys.addOutputComponent("gspath","GPATH","the position on the path calculated using trigonometry"); keys.addOutputComponent("gzpath","GPATH","the distance from the path calculated using trigonometry"); } TrigonometricPathVessel::TrigonometricPathVessel( const vesselbase::VesselOptions& da ): -StoreDataVessel(da), -projdir(ReferenceConfigurationOptions("DIRECTION")), -mydpack1( 1, getAction()->getNumberOfDerivatives() ), -mydpack2( 1, getAction()->getNumberOfDerivatives() ), -mydpack3( 1, getAction()->getNumberOfDerivatives() ), -mypack1( 0, 0, mydpack1 ), -mypack2( 0, 0, mydpack2 ), -mypack3( 0, 0, mydpack3 ) + StoreDataVessel(da), + projdir(ReferenceConfigurationOptions("DIRECTION")), + mydpack1( 1, getAction()->getNumberOfDerivatives() ), + mydpack2( 1, getAction()->getNumberOfDerivatives() ), + mydpack3( 1, getAction()->getNumberOfDerivatives() ), + mypack1( 0, 0, mydpack1 ), + mypack2( 0, 0, mydpack2 ), + mypack3( 0, 0, mydpack3 ) { mymap=dynamic_cast<Mapping*>( getAction() ); plumed_massert( mymap, "Trigonometric path vessel can only be used with mappings"); // Retrieve the index of the property in the underlying mapping if( mymap->getNumberOfProperties()!=1 ) error("cannot use trigonometric paths when there are multiple properties"); - for(unsigned i=0;i<mymap->getFullNumberOfTasks();++i){ - if( mymap->getTaskCode(i)!=mymap->getPositionInFullTaskList(i) ) error("mismatched tasks and codes"); + for(unsigned i=0; i<mymap->getFullNumberOfTasks(); ++i) { + if( mymap->getTaskCode(i)!=mymap->getPositionInFullTaskList(i) ) error("mismatched tasks and codes"); } - mymap->addComponentWithDerivatives("gspath"); mymap->componentIsNotPeriodic("gspath"); + mymap->addComponentWithDerivatives("gspath"); mymap->componentIsNotPeriodic("gspath"); sp=mymap->copyOutput( mymap->getNumberOfComponents()-1 ); sp->resizeDerivatives( mymap->getNumberOfDerivatives() ); - mymap->addComponentWithDerivatives("gzpath"); mymap->componentIsNotPeriodic("gzpath"); + mymap->addComponentWithDerivatives("gzpath"); mymap->componentIsNotPeriodic("gzpath"); zp=mymap->copyOutput( mymap->getNumberOfComponents()-1 ); zp->resizeDerivatives( mymap->getNumberOfDerivatives() ); // Check we have PCA - ReferenceConfiguration* ref0=mymap->getReferenceConfiguration(0); - for(unsigned i=0;i<mymap->getFullNumberOfTasks();++i){ - if( !(mymap->getReferenceConfiguration(i))->pcaIsEnabledForThisReference() ) error("pca must be implemented in order to use trigometric path"); - if( ref0->getName()!=(mymap->getReferenceConfiguration(i))->getName() ) error("cannot use mixed metrics"); - if( mymap->getNumberOfAtoms()!=(mymap->getReferenceConfiguration(i))->getNumberOfReferencePositions() ) error("all frames must use the same set of atoms"); - if( mymap->getNumberOfArguments()!=(mymap->getReferenceConfiguration(i))->getNumberOfReferenceArguments() ) error("all frames must use the same set of arguments"); + ReferenceConfiguration* ref0=mymap->getReferenceConfiguration(0); + for(unsigned i=0; i<mymap->getFullNumberOfTasks(); ++i) { + if( !(mymap->getReferenceConfiguration(i))->pcaIsEnabledForThisReference() ) error("pca must be implemented in order to use trigometric path"); + if( ref0->getName()!=(mymap->getReferenceConfiguration(i))->getName() ) error("cannot use mixed metrics"); + if( mymap->getNumberOfAtoms()!=(mymap->getReferenceConfiguration(i))->getNumberOfReferencePositions() ) error("all frames must use the same set of atoms"); + if( mymap->getNumberOfArguments()!=(mymap->getReferenceConfiguration(i))->getNumberOfReferenceArguments() ) error("all frames must use the same set of arguments"); } cargs.resize( mymap->getNumberOfArguments() ); std::vector<std::string> argument_names( mymap->getNumberOfArguments() ); - for(unsigned i=0;i<mymap->getNumberOfArguments();++i) argument_names[i] = (mymap->getPntrToArgument(i))->getName(); + for(unsigned i=0; i<mymap->getNumberOfArguments(); ++i) argument_names[i] = (mymap->getPntrToArgument(i))->getName(); projdir.setNamesAndAtomNumbers( mymap->getAbsoluteIndexes(), argument_names ); mypack1.resize( mymap->getNumberOfArguments(), mymap->getNumberOfAtoms() ); ref0->setupPCAStorage( mypack1 ); mypack2.resize( mymap->getNumberOfArguments(), mymap->getNumberOfAtoms() ); ref0->setupPCAStorage( mypack2 ); - mypack3.resize( mymap->getNumberOfArguments(), mymap->getNumberOfAtoms() ); - for(unsigned i=0;i<mymap->getNumberOfAtoms();++i){ mypack1.setAtomIndex(i,i); mypack2.setAtomIndex(i,i); mypack3.setAtomIndex(i,i); } + mypack3.resize( mymap->getNumberOfArguments(), mymap->getNumberOfAtoms() ); + for(unsigned i=0; i<mymap->getNumberOfAtoms(); ++i) { mypack1.setAtomIndex(i,i); mypack2.setAtomIndex(i,i); mypack3.setAtomIndex(i,i); } mypack1_stashd_atoms.resize( mymap->getNumberOfAtoms() ); mypack1_stashd_args.resize( mymap->getNumberOfArguments() ); } -std::string TrigonometricPathVessel::description(){ - return "values gspath and gzpath contain the position on and distance from the path calculated using trigonometry"; +std::string TrigonometricPathVessel::description() { + return "values gspath and gzpath contain the position on and distance from the path calculated using trigonometry"; } -void TrigonometricPathVessel::resize(){ +void TrigonometricPathVessel::resize() { StoreDataVessel::resize(); - if( getAction()->derivativesAreRequired() ){ + if( getAction()->derivativesAreRequired() ) { unsigned nderivatives=getAction()->getNumberOfDerivatives(); sp->resizeDerivatives( nderivatives ); zp->resizeDerivatives( nderivatives ); } } -void TrigonometricPathVessel::finish( const std::vector<double>& buffer ){ +void TrigonometricPathVessel::finish( const std::vector<double>& buffer ) { // Store the data calculated during mpi loop StoreDataVessel::finish( buffer ); - // Get current value of all arguments - for(unsigned i=0;i<cargs.size();++i) cargs[i]=mymap->getArgument(i); + // Get current value of all arguments + for(unsigned i=0; i<cargs.size(); ++i) cargs[i]=mymap->getArgument(i); // Determine closest and second closest point to current position double lambda=mymap->getLambda(); std::vector<double> dist( getNumberOfComponents() ), dist2( getNumberOfComponents() );; - retrieveSequentialValue( 0, false, dist ); + retrieveSequentialValue( 0, false, dist ); retrieveSequentialValue( 1, false, dist2 ); iclose1=getStoreIndex(0); iclose2=getStoreIndex(1); - double mindist1=dist[0], mindist2=dist2[0]; - if( lambda>0.0 ){ - mindist1=-std::log( dist[0] ) / lambda; - mindist2=-std::log( dist2[0] ) / lambda; + double mindist1=dist[0], mindist2=dist2[0]; + if( lambda>0.0 ) { + mindist1=-std::log( dist[0] ) / lambda; + mindist2=-std::log( dist2[0] ) / lambda; } - if( mindist2<mindist1 ){ - double tmp=mindist1; mindist1=mindist2; mindist2=tmp; - iclose1=getStoreIndex(1); iclose2=getStoreIndex(0); - } - for(unsigned i=2;i<getNumberOfStoredValues();++i){ - retrieveSequentialValue( i, false, dist ); - double ndist=dist[0]; - if( lambda>0.0 ) ndist=-std::log( dist[0] ) / lambda; - if( ndist<mindist1 ){ - mindist2=mindist1; iclose2=iclose1; - mindist1=ndist; iclose1=getStoreIndex(i); - } else if( ndist<mindist2 ){ - mindist2=ndist; iclose2=getStoreIndex(i); - } + if( mindist2<mindist1 ) { + double tmp=mindist1; mindist1=mindist2; mindist2=tmp; + iclose1=getStoreIndex(1); iclose2=getStoreIndex(0); + } + for(unsigned i=2; i<getNumberOfStoredValues(); ++i) { + retrieveSequentialValue( i, false, dist ); + double ndist=dist[0]; + if( lambda>0.0 ) ndist=-std::log( dist[0] ) / lambda; + if( ndist<mindist1 ) { + mindist2=mindist1; iclose2=iclose1; + mindist1=ndist; iclose1=getStoreIndex(i); + } else if( ndist<mindist2 ) { + mindist2=ndist; iclose2=getStoreIndex(i); + } } // And find third closest point - int isign = iclose1 - iclose2; + int isign = iclose1 - iclose2; if( isign>1 ) isign=1; else if( isign<-1 ) isign=-1; int iclose3 = iclose1 + isign; double v2v2; - // We now have to compute vectors connecting the three closest points to the + // We now have to compute vectors connecting the three closest points to the // new point double v1v1 = (mymap->getReferenceConfiguration( iclose1 ))->calculate( mymap->getPositions(), mymap->getPbc(), mymap->getArguments(), mypack1, true ); - double v3v3 = (mymap->getReferenceConfiguration( iclose2 ))->calculate( mymap->getPositions(), mymap->getPbc(), mymap->getArguments(), mypack3, true ); - if( iclose3<0 || iclose3>=mymap->getFullNumberOfTasks() ){ - ReferenceConfiguration* conf2=mymap->getReferenceConfiguration( iclose1 ); - v2v2=(mymap->getReferenceConfiguration( iclose2 ))->calc( conf2->getReferencePositions(), mymap->getPbc(), mymap->getArguments(), - conf2->getReferenceArguments(), mypack2, true ); - (mymap->getReferenceConfiguration( iclose2 ))->extractDisplacementVector( conf2->getReferencePositions(), mymap->getArguments(), - conf2->getReferenceArguments(), true, false, projdir ); + double v3v3 = (mymap->getReferenceConfiguration( iclose2 ))->calculate( mymap->getPositions(), mymap->getPbc(), mymap->getArguments(), mypack3, true ); + if( iclose3<0 || iclose3>=mymap->getFullNumberOfTasks() ) { + ReferenceConfiguration* conf2=mymap->getReferenceConfiguration( iclose1 ); + v2v2=(mymap->getReferenceConfiguration( iclose2 ))->calc( conf2->getReferencePositions(), mymap->getPbc(), mymap->getArguments(), + conf2->getReferenceArguments(), mypack2, true ); + (mymap->getReferenceConfiguration( iclose2 ))->extractDisplacementVector( conf2->getReferencePositions(), mymap->getArguments(), + conf2->getReferenceArguments(), true, false, projdir ); } else { - ReferenceConfiguration* conf2=mymap->getReferenceConfiguration( iclose3 ); - v2v2=(mymap->getReferenceConfiguration( iclose1 ))->calc( conf2->getReferencePositions(), mymap->getPbc(), mymap->getArguments(), - conf2->getReferenceArguments(), mypack2, true ); - (mymap->getReferenceConfiguration( iclose1 ))->extractDisplacementVector( conf2->getReferencePositions(), mymap->getArguments(), - conf2->getReferenceArguments(), true, false, projdir ); + ReferenceConfiguration* conf2=mymap->getReferenceConfiguration( iclose3 ); + v2v2=(mymap->getReferenceConfiguration( iclose1 ))->calc( conf2->getReferencePositions(), mymap->getPbc(), mymap->getArguments(), + conf2->getReferenceArguments(), mypack2, true ); + (mymap->getReferenceConfiguration( iclose1 ))->extractDisplacementVector( conf2->getReferencePositions(), mymap->getArguments(), + conf2->getReferenceArguments(), true, false, projdir ); } // Stash derivatives of v1v1 - for(unsigned i=0;i<mymap->getNumberOfArguments();++i) mypack1_stashd_args[i]=mypack1.getArgumentDerivative(i); - for(unsigned i=0;i<mymap->getNumberOfAtoms();++i) mypack1_stashd_atoms[i]=mypack1.getAtomDerivative(i); + for(unsigned i=0; i<mymap->getNumberOfArguments(); ++i) mypack1_stashd_args[i]=mypack1.getArgumentDerivative(i); + for(unsigned i=0; i<mymap->getNumberOfAtoms(); ++i) mypack1_stashd_atoms[i]=mypack1.getAtomDerivative(i); // Calculate the dot product of v1 with v2 double v1v2 = (mymap->getReferenceConfiguration(iclose1))->projectDisplacementOnVector( projdir, mymap->getPositions(), mymap->getArguments(), cargs, mypack1 ); - + // This computes s value double spacing = mymap->getPropertyValue( iclose1, 0 ) - mymap->getPropertyValue( iclose2, 0 ); double root = sqrt( v1v2*v1v2 - v2v2 * ( v1v1 - v3v3) ); dx = 0.5 * ( (root + v1v2) / v2v2 - 1.); - double path_s = mymap->getPropertyValue(iclose1, 0) + spacing * dx; sp->set( path_s ); - double fact = 0.25*spacing / v2v2; + double path_s = mymap->getPropertyValue(iclose1, 0) + spacing * dx; sp->set( path_s ); + double fact = 0.25*spacing / v2v2; // Derivative of s wrt arguments - for(unsigned i=0;i<mymap->getNumberOfArguments();++i){ - sp->setDerivative( i, fact*( mypack2.getArgumentDerivative(i) + (v2v2 * (-mypack1_stashd_args[i] + mypack3.getArgumentDerivative(i)) + for(unsigned i=0; i<mymap->getNumberOfArguments(); ++i) { + sp->setDerivative( i, fact*( mypack2.getArgumentDerivative(i) + (v2v2 * (-mypack1_stashd_args[i] + mypack3.getArgumentDerivative(i)) + v1v2*mypack2.getArgumentDerivative(i) )/root ) ); } // Derivative of s wrt atoms unsigned narg=mymap->getNumberOfArguments(); Tensor vir; vir.zero(); fact = 0.5*spacing / v2v2; - if( mymap->getNumberOfAtoms()>0 ){ - for(unsigned i=0;i<mymap->getNumberOfAtoms();++i){ - Vector ader = fact*(( v1v2*mypack1.getAtomDerivative(i) + 0.5*v2v2*(-mypack1_stashd_atoms[i] + mypack3.getAtomDerivative(i) ) )/root + mypack1.getAtomDerivative(i) ); - for(unsigned k=0;k<3;++k) sp->setDerivative( narg+3*i+k, ader[k] ); - vir-=Tensor( mymap->getPosition(i), ader ); - } - // Set the virial - unsigned nbase=narg+3*mymap->getNumberOfAtoms(); - for(unsigned i=0;i<3;++i) for(unsigned j=0;j<3;++j) sp->setDerivative( nbase+3*i+j, vir(i,j) ); + if( mymap->getNumberOfAtoms()>0 ) { + for(unsigned i=0; i<mymap->getNumberOfAtoms(); ++i) { + Vector ader = fact*(( v1v2*mypack1.getAtomDerivative(i) + 0.5*v2v2*(-mypack1_stashd_atoms[i] + mypack3.getAtomDerivative(i) ) )/root + mypack1.getAtomDerivative(i) ); + for(unsigned k=0; k<3; ++k) sp->setDerivative( narg+3*i+k, ader[k] ); + vir-=Tensor( mymap->getPosition(i), ader ); + } + // Set the virial + unsigned nbase=narg+3*mymap->getNumberOfAtoms(); + for(unsigned i=0; i<3; ++i) for(unsigned j=0; j<3; ++j) sp->setDerivative( nbase+3*i+j, vir(i,j) ); } // Now compute z value ReferenceConfiguration* conf2=mymap->getReferenceConfiguration( iclose1 ); - double v4v4=(mymap->getReferenceConfiguration( iclose2 ))->calc( conf2->getReferencePositions(), mymap->getPbc(), mymap->getArguments(), - conf2->getReferenceArguments(), mypack2, true ); + double v4v4=(mymap->getReferenceConfiguration( iclose2 ))->calc( conf2->getReferencePositions(), mymap->getPbc(), mymap->getArguments(), + conf2->getReferenceArguments(), mypack2, true ); // Extract vector connecting frames (mymap->getReferenceConfiguration( iclose2 ))->extractDisplacementVector( conf2->getReferencePositions(), mymap->getArguments(), - conf2->getReferenceArguments(), true, false, projdir ); + conf2->getReferenceArguments(), true, false, projdir ); // Calculate projection of vector on line connnecting frames double proj = (mymap->getReferenceConfiguration(iclose1))->projectDisplacementOnVector( projdir, mymap->getPositions(), mymap->getArguments(), cargs, mypack1 ); - double path_z = v1v1 + dx*dx*v4v4 - 2*dx*proj; + double path_z = v1v1 + dx*dx*v4v4 - 2*dx*proj; - // Derivatives for z path - path_z = sqrt(path_z); zp->set( path_z ); vir.zero(); - for(unsigned i=0;i<mymap->getNumberOfArguments();++i) zp->setDerivative( i, (mypack1_stashd_args[i] - 2*dx*mypack1.getArgumentDerivative(i))/(2.0*path_z) ); + // Derivatives for z path + path_z = sqrt(path_z); zp->set( path_z ); vir.zero(); + for(unsigned i=0; i<mymap->getNumberOfArguments(); ++i) zp->setDerivative( i, (mypack1_stashd_args[i] - 2*dx*mypack1.getArgumentDerivative(i))/(2.0*path_z) ); // Derivative wrt atoms - if( mymap->getNumberOfAtoms()>0 ){ - for(unsigned i=0;i<mymap->getNumberOfAtoms();++i){ - Vector dxder; for(unsigned k=0;k<3;++k) dxder[k] = ( 2*v4v4*dx - 2*proj )*spacing*sp->getDerivative( narg + 3*i+k ); - Vector ader = ( mypack1_stashd_atoms[i] - 2.*dx*mypack1.getAtomDerivative(i) + dxder )/ (2.0*path_z); - for(unsigned k=0;k<3;++k) zp->setDerivative( narg+3*i+k, ader[k] ); - vir-=Tensor( mymap->getPosition(i), ader ); - } - // Set the virial - unsigned nbase=narg+3*mymap->getNumberOfAtoms(); - for(unsigned i=0;i<3;++i) for(unsigned j=0;j<3;++j) zp->setDerivative( nbase+3*i+j, vir(i,j) ); + if( mymap->getNumberOfAtoms()>0 ) { + for(unsigned i=0; i<mymap->getNumberOfAtoms(); ++i) { + Vector dxder; for(unsigned k=0; k<3; ++k) dxder[k] = ( 2*v4v4*dx - 2*proj )*spacing*sp->getDerivative( narg + 3*i+k ); + Vector ader = ( mypack1_stashd_atoms[i] - 2.*dx*mypack1.getAtomDerivative(i) + dxder )/ (2.0*path_z); + for(unsigned k=0; k<3; ++k) zp->setDerivative( narg+3*i+k, ader[k] ); + vir-=Tensor( mymap->getPosition(i), ader ); + } + // Set the virial + unsigned nbase=narg+3*mymap->getNumberOfAtoms(); + for(unsigned i=0; i<3; ++i) for(unsigned j=0; j<3; ++j) zp->setDerivative( nbase+3*i+j, vir(i,j) ); } } -bool TrigonometricPathVessel::applyForce( std::vector<double>& forces ){ - std::vector<double> tmpforce( forces.size(), 0.0 ); - forces.assign(forces.size(),0.0); bool wasforced=false; - if( sp->applyForce( tmpforce ) ){ - wasforced=true; - for(unsigned j=0;j<forces.size();++j) forces[j]+=tmpforce[j]; +bool TrigonometricPathVessel::applyForce( std::vector<double>& forces ) { + std::vector<double> tmpforce( forces.size(), 0.0 ); + forces.assign(forces.size(),0.0); bool wasforced=false; + if( sp->applyForce( tmpforce ) ) { + wasforced=true; + for(unsigned j=0; j<forces.size(); ++j) forces[j]+=tmpforce[j]; } tmpforce.assign(forces.size(),0.0); - if( zp->applyForce( tmpforce ) ){ - wasforced=true; - for(unsigned j=0;j<forces.size();++j) forces[j]+=tmpforce[j]; + if( zp->applyForce( tmpforce ) ) { + wasforced=true; + for(unsigned j=0; j<forces.size(); ++j) forces[j]+=tmpforce[j]; } return wasforced; } diff --git a/src/mapping/TrigonometricPathVessel.h b/src/mapping/TrigonometricPathVessel.h index 630514a75..2f36c99b1 100644 --- a/src/mapping/TrigonometricPathVessel.h +++ b/src/mapping/TrigonometricPathVessel.h @@ -32,9 +32,9 @@ namespace PLMD { namespace mapping { class TrigonometricPathVessel : public vesselbase::StoreDataVessel { -friend class AdaptivePath; + friend class AdaptivePath; private: - Value* sp; + Value* sp; Value* zp; Mapping* mymap; double dx; diff --git a/src/mapping/ZpathVessel.cpp b/src/mapping/ZpathVessel.cpp index ee3d9fa88..9c8606a8f 100644 --- a/src/mapping/ZpathVessel.cpp +++ b/src/mapping/ZpathVessel.cpp @@ -40,24 +40,24 @@ public: PLUMED_REGISTER_VESSEL(ZpathVessel,"ZPATH") -void ZpathVessel::registerKeywords( Keywords& keys ){ +void ZpathVessel::registerKeywords( Keywords& keys ) { FunctionVessel::registerKeywords(keys); } -void ZpathVessel::reserveKeyword( Keywords& keys ){ +void ZpathVessel::reserveKeyword( Keywords& keys ) { keys.reserve("vessel","ZPATH","calculate the distance from the low dimensionality manifold"); keys.addOutputComponent("zpath","ZPATH","the distance from the path"); } ZpathVessel::ZpathVessel( const vesselbase::VesselOptions& da ): -FunctionVessel(da) + FunctionVessel(da) { Mapping* mymap=dynamic_cast<Mapping*>( getAction() ); plumed_massert( mymap, "ZpathVessel should only be used with mappings"); invlambda = 1.0 / mymap->getLambda(); usetol=true; } -std::string ZpathVessel::value_descriptor(){ +std::string ZpathVessel::value_descriptor() { return "the distance from the low-dimensional manifold"; } @@ -65,10 +65,10 @@ double ZpathVessel::calcTransform( const double& val, double& dv ) const { dv=0.0; return 1.0; } -double ZpathVessel::finalTransform( const double& val, double& dv ){ - dv = -invlambda / val; - return -invlambda*std::log( val ); -} +double ZpathVessel::finalTransform( const double& val, double& dv ) { + dv = -invlambda / val; + return -invlambda*std::log( val ); +} } } diff --git a/src/multicolvar/ActionVolume.cpp b/src/multicolvar/ActionVolume.cpp index d490ef31d..5f12881e1 100644 --- a/src/multicolvar/ActionVolume.cpp +++ b/src/multicolvar/ActionVolume.cpp @@ -24,7 +24,7 @@ namespace PLMD { namespace multicolvar { -void ActionVolume::registerKeywords( Keywords& keys ){ +void ActionVolume::registerKeywords( Keywords& keys ) { VolumeGradientBase::registerKeywords( keys ); if( keys.reserved("VMEAN") ) keys.use("VMEAN"); keys.use("MEAN"); keys.use("LESS_THAN"); keys.use("MORE_THAN"); @@ -35,39 +35,39 @@ void ActionVolume::registerKeywords( Keywords& keys ){ } ActionVolume::ActionVolume(const ActionOptions&ao): -Action(ao), -VolumeGradientBase(ao) + Action(ao), + VolumeGradientBase(ao) { // Find number of quantities - if( getPntrToMultiColvar()->isDensity() ) nquantities=2; // Value + weight + if( getPntrToMultiColvar()->isDensity() ) nquantities=2; // Value + weight else if( getPntrToMultiColvar()->getNumberOfQuantities()==2 ) nquantities=2; // Value + weight - else nquantities = 1 + getPntrToMultiColvar()->getNumberOfQuantities()-2 + 1; // Norm + vector + weight + else nquantities = 1 + getPntrToMultiColvar()->getNumberOfQuantities()-2 + 1; // Norm + vector + weight // Output some nice information std::string functype=getPntrToMultiColvar()->getName(); std::transform( functype.begin(), functype.end(), functype.begin(), tolower ); - log.printf(" calculating %s inside region of insterest\n",functype.c_str() ); + log.printf(" calculating %s inside region of insterest\n",functype.c_str() ); parseFlag("OUTSIDE",not_in); sigma=0.0; - if( keywords.exists("SIGMA") ) parse("SIGMA",sigma); - if( keywords.exists("KERNEL") ) parse("KERNEL",kerneltype); - - if( getPntrToMultiColvar()->isDensity() ){ - std::string input; - addVessel( "SUM", input, -1 ); // -1 here means that this value will be named getLabel() - } + if( keywords.exists("SIGMA") ) parse("SIGMA",sigma); + if( keywords.exists("KERNEL") ) parse("KERNEL",kerneltype); + + if( getPntrToMultiColvar()->isDensity() ) { + std::string input; + addVessel( "SUM", input, -1 ); // -1 here means that this value will be named getLabel() + } readVesselKeywords(); } void ActionVolume::calculateAllVolumes( const unsigned& curr, MultiValue& outvals ) const { Vector catom_pos=getPntrToMultiColvar()->getCentralAtomPos( curr ); - double weight; Vector wdf; Tensor vir; std::vector<Vector> refders( getNumberOfAtoms() ); - weight=calculateNumberInside( catom_pos, wdf, vir, refders ); - if( not_in ){ - weight = 1.0 - weight; wdf *= -1.; vir *=-1; - for(unsigned i=0;i<refders.size();++i) refders[i]*=-1; - } + double weight; Vector wdf; Tensor vir; std::vector<Vector> refders( getNumberOfAtoms() ); + weight=calculateNumberInside( catom_pos, wdf, vir, refders ); + if( not_in ) { + weight = 1.0 - weight; wdf *= -1.; vir *=-1; + for(unsigned i=0; i<refders.size(); ++i) refders[i]*=-1; + } setNumberInVolume( 0, curr, weight, wdf, vir, refders, outvals ); } diff --git a/src/multicolvar/ActionVolume.h b/src/multicolvar/ActionVolume.h index fe69bd050..f71cbca39 100644 --- a/src/multicolvar/ActionVolume.h +++ b/src/multicolvar/ActionVolume.h @@ -31,8 +31,8 @@ namespace multicolvar { /** \ingroup INHERIT This is the abstract base class to use for implementing a new way of definining a particular region of the simulation -box. You can use this to calculate the number of atoms inside that part or the average value of a quantity like the -coordination number inside that part of the cell. +box. You can use this to calculate the number of atoms inside that part or the average value of a quantity like the +coordination number inside that part of the cell. */ class ActionVolume : public VolumeGradientBase { @@ -65,7 +65,7 @@ public: inline unsigned ActionVolume::getNumberOfQuantities() const { return nquantities; -} +} inline double ActionVolume::getSigma() const { @@ -78,8 +78,8 @@ std::string ActionVolume::getKernelType() const { } inline -unsigned ActionVolume::getCentralAtomElementIndex(){ - return 1; +unsigned ActionVolume::getCentralAtomElementIndex() { + return 1; } } diff --git a/src/multicolvar/AlphaBeta.cpp b/src/multicolvar/AlphaBeta.cpp index b55788a04..01379c583 100644 --- a/src/multicolvar/AlphaBeta.cpp +++ b/src/multicolvar/AlphaBeta.cpp @@ -29,17 +29,17 @@ using namespace std; -namespace PLMD{ -namespace multicolvar{ +namespace PLMD { +namespace multicolvar { -//+PLUMEDOC COLVAR ALPHABETA +//+PLUMEDOC COLVAR ALPHABETA /* Measures a distance including pbc between the instantaneous values of a set of torsional angles and set of reference values. This colvar calculates the following quantity. \f[ -s = \frac{1}{2} \sum_i \left[ 1 + \cos( \phi_i - \phi_i^{\textrm{Ref}} ) \right] +s = \frac{1}{2} \sum_i \left[ 1 + \cos( \phi_i - \phi_i^{\textrm{Ref}} ) \right] \f] where the \f$\phi_i\f$ values are the instantaneous values for the \ref TORSION angles of interest. @@ -51,8 +51,8 @@ The following provides an example of the input for an alpha beta similarity. \verbatim ALPHABETA ... -ATOMS1=168,170,172,188 REFERENCE1=3.14 -ATOMS2=170,172,188,190 REFERENCE2=3.14 +ATOMS1=168,170,172,188 REFERENCE1=3.14 +ATOMS2=170,172,188,190 REFERENCE2=3.14 ATOMS3=188,190,192,230 REFERENCE3=3.14 LABEL=ab ... ALPHABETA @@ -63,16 +63,16 @@ Because all the reference values are the same we can calculate the same quantity \verbatim ALPHABETA ... -ATOMS1=168,170,172,188 REFERENCE=3.14 -ATOMS2=170,172,188,190 -ATOMS3=188,190,192,230 +ATOMS1=168,170,172,188 REFERENCE=3.14 +ATOMS2=170,172,188,190 +ATOMS3=188,190,192,230 LABEL=ab ... ALPHABETA PRINT ARG=ab FILE=colvar STRIDE=10 \endverbatim Writing out the atoms involved in all the torsions in this way can be rather tedious. Thankfully if you are working with protein you -can avoid this by using the \ref MOLINFO command. PLUMED uses the pdb file that you provide to this command to learn +can avoid this by using the \ref MOLINFO command. PLUMED uses the pdb file that you provide to this command to learn about the topology of the protein molecule. This means that you can specify torsion angles using the following syntax: \verbatim @@ -82,11 +82,11 @@ ATOMS1=@phi-3 REFERENCE=3.14 ATOMS2=@psi-3 ATOMS3=@phi-4 LABEL=ab -... ALPHABETA +... ALPHABETA PRINT ARG=ab FILE=colvar STRIDE=10 \endverbatim -Here, \@phi-3 tells plumed that you would like to calculate the \f$\phi\f$ angle in the third residue of the protein. +Here, \@phi-3 tells plumed that you would like to calculate the \f$\phi\f$ angle in the third residue of the protein. Similarly \@psi-4 tells plumed that you want to calculate the \f$\psi\f$ angle of the 4th residue of the protein. @@ -100,27 +100,27 @@ public: static void registerKeywords( Keywords& keys ); explicit AlphaBeta(const ActionOptions&); virtual double compute( const unsigned& tindex, AtomValuePack& myatoms ) const ; - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } }; PLUMED_REGISTER_ACTION(AlphaBeta,"ALPHABETA") -void AlphaBeta::registerKeywords( Keywords& keys ){ +void AlphaBeta::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); keys.add("numbered","ATOMS","the atoms involved in each of the alpha-beta variables you wish to calculate. " - "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one alpha-beta values will be " - "calculated for each ATOM keyword you specify (all ATOM keywords should " - "specify the indices of four atoms). The eventual number of quantities calculated by this " - "action will depend on what functions of the distribution you choose to calculate."); + "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one alpha-beta values will be " + "calculated for each ATOM keyword you specify (all ATOM keywords should " + "specify the indices of four atoms). The eventual number of quantities calculated by this " + "action will depend on what functions of the distribution you choose to calculate."); keys.reset_style("ATOMS","atoms"); - keys.add("numbered","REFERENCE","the reference values for each of the torsional angles. If you use a single REFERENCE value the " - "same reference value is used for all torsions"); + keys.add("numbered","REFERENCE","the reference values for each of the torsional angles. If you use a single REFERENCE value the " + "same reference value is used for all torsions"); keys.reset_style("REFERENCE","compulsory"); } AlphaBeta::AlphaBeta(const ActionOptions&ao): -Action(ao), -MultiColvarBase(ao) + Action(ao), + MultiColvarBase(ao) { // Read in the atoms std::vector<AtomNumber> all_atoms; @@ -129,28 +129,28 @@ MultiColvarBase(ao) // Resize target target.resize( getFullNumberOfTasks() ); // Setup central atom indices - std::vector<bool> catom_ind(4, false); + std::vector<bool> catom_ind(4, false); catom_ind[1]=catom_ind[2]=true; setAtomsForCentralAtom( catom_ind ); // Read in reference values unsigned ntarget=0; - for(unsigned i=0;i<target.size();++i){ - if( !parseNumbered( "REFERENCE", i+1, target[i] ) ) break; - ntarget++; + for(unsigned i=0; i<target.size(); ++i) { + if( !parseNumbered( "REFERENCE", i+1, target[i] ) ) break; + ntarget++; } - if( ntarget==0 ){ - parse("REFERENCE",target[0]); - for(unsigned i=1;i<target.size();++i) target[i]=target[0]; - } else if( ntarget!=target.size() ){ - error("found wrong number of REFERENCE values"); + if( ntarget==0 ) { + parse("REFERENCE",target[0]); + for(unsigned i=1; i<target.size(); ++i) target[i]=target[0]; + } else if( ntarget!=target.size() ) { + error("found wrong number of REFERENCE values"); } // And setup the ActionWithVessel - if( getNumberOfVessels()==0 ){ - std::string fake_input; - addVessel( "SUM", fake_input, -1 ); // -1 here means that this value will be named getLabel() - readVesselKeywords(); // This makes sure resizing is done + if( getNumberOfVessels()==0 ) { + std::string fake_input; + addVessel( "SUM", fake_input, -1 ); // -1 here means that this value will be named getLabel() + readVesselKeywords(); // This makes sure resizing is done } // And check everything has been read in correctly diff --git a/src/multicolvar/Angles.cpp b/src/multicolvar/Angles.cpp index 2c82eb490..a42233cbd 100644 --- a/src/multicolvar/Angles.cpp +++ b/src/multicolvar/Angles.cpp @@ -30,10 +30,10 @@ using namespace std; -namespace PLMD{ -namespace multicolvar{ +namespace PLMD { +namespace multicolvar { -//+PLUMEDOC MCOLVAR ANGLES +//+PLUMEDOC MCOLVAR ANGLES /* Calculate functions of the distribution of angles . @@ -41,7 +41,7 @@ You can use this command to calculate functions such as: \f[ f(x) = \sum_{ijk} g( \theta_{ijk} ) -\f] +\f] Alternatively you can use this command to calculate functions such as: @@ -50,7 +50,7 @@ f(x) = \sum_{ijk} s(r_{ij})s(r_{jk}) g(\theta_{ijk}) \f] where \f$s(r)\f$ is a \ref switchingfunction. This second form means that you can -use this to calculate functions of the angles in the first coordination sphere of +use this to calculate functions of the angles in the first coordination sphere of an atom / molecule \cite lj-recon. \par Examples @@ -60,18 +60,18 @@ print it to a file \verbatim ANGLES ATOMS1=1,2,3 ATOMS2=4,5,6 MEAN LABEL=a1 -PRINT ARG=a1.mean FILE=colvar +PRINT ARG=a1.mean FILE=colvar \endverbatim The following example tells plumed to calculate all angles involving at least one atom from GROUPA and two atoms from GROUPB in which the distances are less than 1.0. The number of angles between \f$\frac{\pi}{4}\f$ and -\f$\frac{3\pi}{4}\f$ is then output +\f$\frac{3\pi}{4}\f$ is then output \verbatim ANGLES GROUPA=1-10 GROUPB=11-100 BETWEEN={GAUSSIAN LOWER=0.25pi UPPER=0.75pi} SWITCH={GAUSSIAN R_0=1.0} LABEL=a1 PRINT ARG=a1.between FILE=colvar -\endverbatim +\endverbatim This final example instructs plumed to calculate all the angles in the first coordination spheres of the atoms. A discretized-normalized histogram of the distribution is then output @@ -97,79 +97,79 @@ public: virtual double compute( const unsigned& tindex, AtomValuePack& ) const ; /// Returns the number of coordinates of the field double calculateWeight( const unsigned& taskCode, const double& weight, AtomValuePack& ) const ; - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } }; PLUMED_REGISTER_ACTION(Angles,"ANGLES") -void Angles::registerKeywords( Keywords& keys ){ +void Angles::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); - keys.use("MEAN"); keys.use("LESS_THAN"); + keys.use("MEAN"); keys.use("LESS_THAN"); keys.use("BETWEEN"); keys.use("HISTOGRAM"); keys.use("MORE_THAN"); // Could also add Region here in theory keys.add("numbered","ATOMS","the atoms involved in each of the angles you wish to calculate. " - "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one angle will be " - "calculated for each ATOM keyword you specify (all ATOM keywords should " - "provide the indices of three atoms). The eventual number of quantities calculated by this " - "action will depend on what functions of the distribution you choose to calculate."); + "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one angle will be " + "calculated for each ATOM keyword you specify (all ATOM keywords should " + "provide the indices of three atoms). The eventual number of quantities calculated by this " + "action will depend on what functions of the distribution you choose to calculate."); keys.reset_style("ATOMS","atoms"); keys.add("atoms-1","GROUP","Calculate angles for each distinct set of three atoms in the group"); keys.add("atoms-2","GROUPA","A group of central atoms about which angles should be calculated"); keys.add("atoms-2","GROUPB","When used in conjuction with GROUPA this keyword instructs plumed " - "to calculate all distinct angles involving one atom from GROUPA " - "and two atoms from GROUPB. The atom from GROUPA is the central atom."); - keys.add("atoms-3","GROUPC","This must be used in conjuction with GROUPA and GROUPB. All angles " - "involving one atom from GROUPA, one atom from GROUPB and one atom from " - "GROUPC are calculated. The GROUPA atoms are assumed to be the central " - "atoms"); + "to calculate all distinct angles involving one atom from GROUPA " + "and two atoms from GROUPB. The atom from GROUPA is the central atom."); + keys.add("atoms-3","GROUPC","This must be used in conjuction with GROUPA and GROUPB. All angles " + "involving one atom from GROUPA, one atom from GROUPB and one atom from " + "GROUPC are calculated. The GROUPA atoms are assumed to be the central " + "atoms"); keys.add("optional","SWITCH","A switching function that ensures that only angles between atoms that " - "are within a certain fixed cutoff are calculated. The following provides " - "information on the \\ref switchingfunction that are available."); + "are within a certain fixed cutoff are calculated. The following provides " + "information on the \\ref switchingfunction that are available."); keys.add("optional","SWITCHA","A switching function on the distance between the atoms in group A and the atoms in " - "group B"); + "group B"); keys.add("optional","SWITCHB","A switching function on the distance between the atoms in group A and the atoms in " - "group B"); + "group B"); } Angles::Angles(const ActionOptions&ao): -Action(ao), -MultiColvarBase(ao), -use_sf(false) + Action(ao), + MultiColvarBase(ao), + use_sf(false) { std::string sfinput,errors; parse("SWITCH",sfinput); - if( sfinput.length()>0 ){ + if( sfinput.length()>0 ) { + use_sf=true; + weightHasDerivatives=true; + sf1.set(sfinput,errors); + if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); + sf2.set(sfinput,errors); + if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); + log.printf(" only calculating angles for atoms separated by less than %s\n", sf1.description().c_str() ); + } else { + parse("SWITCHA",sfinput); + if(sfinput.length()>0) { use_sf=true; weightHasDerivatives=true; sf1.set(sfinput,errors); - if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); + if( errors.length()!=0 ) error("problem reading SWITCHA keyword : " + errors ); + sfinput.clear(); parse("SWITCHB",sfinput); + if(sfinput.length()==0) error("found SWITCHA keyword without SWITCHB"); sf2.set(sfinput,errors); - if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); - log.printf(" only calculating angles for atoms separated by less than %s\n", sf1.description().c_str() ); - } else { - parse("SWITCHA",sfinput); - if(sfinput.length()>0){ - use_sf=true; - weightHasDerivatives=true; - sf1.set(sfinput,errors); - if( errors.length()!=0 ) error("problem reading SWITCHA keyword : " + errors ); - sfinput.clear(); parse("SWITCHB",sfinput); - if(sfinput.length()==0) error("found SWITCHA keyword without SWITCHB"); - sf2.set(sfinput,errors); - if( errors.length()!=0 ) error("problem reading SWITCHB keyword : " + errors ); - log.printf(" only calculating angles when the distance between GROUPA and GROUPB atoms is less than %s\n", sf1.description().c_str() ); - log.printf(" only calculating angles when the distance between GROUPA and GROUPC atoms is less than %s\n", sf2.description().c_str() ); - } + if( errors.length()!=0 ) error("problem reading SWITCHB keyword : " + errors ); + log.printf(" only calculating angles when the distance between GROUPA and GROUPB atoms is less than %s\n", sf1.description().c_str() ); + log.printf(" only calculating angles when the distance between GROUPA and GROUPC atoms is less than %s\n", sf2.description().c_str() ); + } } // Read in the atoms std::vector<AtomNumber> all_atoms; readGroupKeywords( "GROUP", "GROUPA", "GROUPB", "GROUPC", false, true, all_atoms ); if( atom_lab.size()==0 ) readAtomsLikeKeyword( "ATOMS", 3, all_atoms ); setupMultiColvarBase( all_atoms ); - // Set cutoff for link cells - if( use_sf ){ - setLinkCellCutoff( sf1.get_dmax() ); - rcut2_1=sf1.get_dmax()*sf1.get_dmax(); - rcut2_2=sf2.get_dmax()*sf2.get_dmax(); + // Set cutoff for link cells + if( use_sf ) { + setLinkCellCutoff( sf1.get_dmax() ); + rcut2_1=sf1.get_dmax()*sf1.get_dmax(); + rcut2_2=sf2.get_dmax()*sf2.get_dmax(); } // And check everything has been read in correctly @@ -180,23 +180,23 @@ use_sf(false) } double Angles::calculateWeight( const unsigned& taskCode, const double& weight, AtomValuePack& myatoms ) const { - if(!use_sf) return 1.0; + if(!use_sf) return 1.0; Vector dij=getSeparation( myatoms.getPosition(0), myatoms.getPosition(2) ); Vector dik=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); double w1, w2, dw1, dw2, wtot; - double ldij = dij.modulo2(), ldik = dik.modulo2(); + double ldij = dij.modulo2(), ldik = dik.modulo2(); - if( use_sf ){ - if( ldij>rcut2_1 || ldik>rcut2_2 ) return 0.0; + if( use_sf ) { + if( ldij>rcut2_1 || ldik>rcut2_2 ) return 0.0; } w1=sf1.calculateSqr( ldij, dw1 ); w2=sf2.calculateSqr( ldik, dw2 ); - wtot=w1*w2; dw1*=weight*w2; dw2*=weight*w1; + wtot=w1*w2; dw1*=weight*w2; dw2*=weight*w1; addAtomDerivatives( 0, 1, dw2*dik, myatoms ); - addAtomDerivatives( 0, 0, -dw1*dij - dw2*dik, myatoms ); + addAtomDerivatives( 0, 0, -dw1*dij - dw2*dik, myatoms ); addAtomDerivatives( 0, 2, dw1*dij, myatoms ); myatoms.addBoxDerivatives( 0, (-dw1)*Tensor(dij,dij) + (-dw2)*Tensor(dik,dik) ); return wtot; @@ -206,7 +206,7 @@ double Angles::compute( const unsigned& tindex, AtomValuePack& myatoms ) const { Vector dij=getSeparation( myatoms.getPosition(0), myatoms.getPosition(2) ); Vector dik=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); - Vector ddij,ddik; PLMD::Angle a; + Vector ddij,ddik; PLMD::Angle a; double angle=a.compute(dij,dik,ddij,ddik); // And finish the calculation diff --git a/src/multicolvar/AtomValuePack.cpp b/src/multicolvar/AtomValuePack.cpp index 6126aa4cb..99a52a8fb 100644 --- a/src/multicolvar/AtomValuePack.cpp +++ b/src/multicolvar/AtomValuePack.cpp @@ -27,67 +27,67 @@ namespace PLMD { namespace multicolvar { AtomValuePack::AtomValuePack( MultiValue& vals, MultiColvarBase const * mcolv ): -myvals(vals), -mycolv(mcolv), -natoms(0), -indices( vals.getIndices() ), -sort_vector( vals.getSortIndices() ), -myatoms( vals.getAtomVector() ) + myvals(vals), + mycolv(mcolv), + natoms(0), + indices( vals.getIndices() ), + sort_vector( vals.getSortIndices() ), + myatoms( vals.getAtomVector() ) { - if( indices.size()!=mcolv->getNumberOfAtoms() ){ - indices.resize( mcolv->getNumberOfAtoms() ); - sort_vector.resize( mcolv->getNumberOfAtoms() ); + if( indices.size()!=mcolv->getNumberOfAtoms() ) { + indices.resize( mcolv->getNumberOfAtoms() ); + sort_vector.resize( mcolv->getNumberOfAtoms() ); myatoms.resize( mcolv->getNumberOfAtoms() ); } } -unsigned AtomValuePack::setupAtomsFromLinkCells( const std::vector<unsigned>& cind, const Vector& cpos, const LinkCells& linkcells ){ - natoms=cind.size(); for(unsigned i=0;i<natoms;++i) indices[i]=cind[i]; - linkcells.retrieveNeighboringAtoms( cpos, natoms, indices ); - for(unsigned i=0;i<natoms;++i) myatoms[i]=mycolv->getPositionOfAtomForLinkCells( indices[i] ) - cpos; +unsigned AtomValuePack::setupAtomsFromLinkCells( const std::vector<unsigned>& cind, const Vector& cpos, const LinkCells& linkcells ) { + natoms=cind.size(); for(unsigned i=0; i<natoms; ++i) indices[i]=cind[i]; + linkcells.retrieveNeighboringAtoms( cpos, natoms, indices ); + for(unsigned i=0; i<natoms; ++i) myatoms[i]=mycolv->getPositionOfAtomForLinkCells( indices[i] ) - cpos; if( mycolv->usesPbc() ) mycolv->applyPbc( myatoms, natoms ); return natoms; } -void AtomValuePack::updateUsingIndices(){ +void AtomValuePack::updateUsingIndices() { if( myvals.updateComplete() ) return; unsigned jactive=0; - for(unsigned i=0;i<natoms;++i){ - unsigned base=3*indices[i]; - if( myvals.isActive( base ) ){ sort_vector[jactive]=indices[i]; jactive++; } + for(unsigned i=0; i<natoms; ++i) { + unsigned base=3*indices[i]; + if( myvals.isActive( base ) ) { sort_vector[jactive]=indices[i]; jactive++; } } std::sort( sort_vector.begin(), sort_vector.begin()+jactive ); myvals.emptyActiveMembers(); - for(unsigned i=0;i<jactive;++i){ - unsigned base=3*sort_vector[i]; // indices[i]; - myvals.putIndexInActiveArray( base ); - myvals.putIndexInActiveArray( base + 1 ); - myvals.putIndexInActiveArray( base + 2 ); + for(unsigned i=0; i<jactive; ++i) { + unsigned base=3*sort_vector[i]; // indices[i]; + myvals.putIndexInActiveArray( base ); + myvals.putIndexInActiveArray( base + 1 ); + myvals.putIndexInActiveArray( base + 2 ); } unsigned nvir=3*mycolv->getNumberOfAtoms(); - if( myvals.isActive( nvir ) ){ - for(unsigned i=0;i<9;++i) myvals.putIndexInActiveArray( nvir + i ); + if( myvals.isActive( nvir ) ) { + for(unsigned i=0; i<9; ++i) myvals.putIndexInActiveArray( nvir + i ); } myvals.completeUpdate(); } -void AtomValuePack::addComDerivatives( const int& ind, const Vector& der, CatomPack& catom_der ){ - if( ind<0 ){ - for(unsigned ider=0;ider<catom_der.getNumberOfAtomsWithDerivatives();++ider){ - unsigned jder=3*catom_der.getIndex(ider); - myvals.addTemporyDerivative( jder+0, catom_der.getDerivative(ider,0,der) ); - myvals.addTemporyDerivative( jder+1, catom_der.getDerivative(ider,1,der) ); - myvals.addTemporyDerivative( jder+2, catom_der.getDerivative(ider,2,der) ); - } +void AtomValuePack::addComDerivatives( const int& ind, const Vector& der, CatomPack& catom_der ) { + if( ind<0 ) { + for(unsigned ider=0; ider<catom_der.getNumberOfAtomsWithDerivatives(); ++ider) { + unsigned jder=3*catom_der.getIndex(ider); + myvals.addTemporyDerivative( jder+0, catom_der.getDerivative(ider,0,der) ); + myvals.addTemporyDerivative( jder+1, catom_der.getDerivative(ider,1,der) ); + myvals.addTemporyDerivative( jder+2, catom_der.getDerivative(ider,2,der) ); + } } else { - for(unsigned ider=0;ider<catom_der.getNumberOfAtomsWithDerivatives();++ider){ - unsigned jder=3*catom_der.getIndex(ider); - myvals.addDerivative( ind, jder+0, catom_der.getDerivative(ider,0,der) ); - myvals.addDerivative( ind, jder+1, catom_der.getDerivative(ider,1,der) ); - myvals.addDerivative( ind, jder+2, catom_der.getDerivative(ider,2,der) ); - } + for(unsigned ider=0; ider<catom_der.getNumberOfAtomsWithDerivatives(); ++ider) { + unsigned jder=3*catom_der.getIndex(ider); + myvals.addDerivative( ind, jder+0, catom_der.getDerivative(ider,0,der) ); + myvals.addDerivative( ind, jder+1, catom_der.getDerivative(ider,1,der) ); + myvals.addDerivative( ind, jder+2, catom_der.getDerivative(ider,2,der) ); + } } } diff --git a/src/multicolvar/AtomValuePack.h b/src/multicolvar/AtomValuePack.h index e4b059653..c98aa3265 100644 --- a/src/multicolvar/AtomValuePack.h +++ b/src/multicolvar/AtomValuePack.h @@ -34,8 +34,8 @@ namespace multicolvar { class CatomPack; class AtomValuePack { -friend class MultiColvarBase; -friend class LocalAverage; + friend class MultiColvarBase; + friend class LocalAverage; private: /// Copy of the values that we are adding to MultiValue& myvals; @@ -50,9 +50,9 @@ private: /// This holds atom positions std::vector<Vector>& myatoms; /// - void addDerivative( const unsigned& , const unsigned& , const double& ); + void addDerivative( const unsigned&, const unsigned&, const double& ); /// - void addAtomsDerivatives( const unsigned& , const unsigned& , const Vector& ); + void addAtomsDerivatives( const unsigned&, const unsigned&, const Vector& ); /// void addTemporyAtomsDerivatives( const unsigned& jder, const Vector& der ); public: @@ -60,7 +60,7 @@ public: /// Set the number of atoms void setNumberOfAtoms( const unsigned& ); /// Set the index for one of the atoms - void setIndex( const unsigned& , const unsigned& ); + void setIndex( const unsigned&, const unsigned& ); /// void setAtomIndex( const unsigned& j, const unsigned& ind ); /// @@ -76,13 +76,13 @@ public: /// Get the position of the ith atom Vector& getPosition( const unsigned& ); /// - void setValue( const unsigned& , const double& ); + void setValue( const unsigned&, const double& ); /// void addValue( const unsigned& ival, const double& vv ); /// double getValue( const unsigned& ) const ; /// - void addBoxDerivatives( const unsigned& , const Tensor& ); + void addBoxDerivatives( const unsigned&, const Tensor& ); /// void addTemporyBoxDerivatives( const Tensor& vir ); /// @@ -90,13 +90,13 @@ public: /// void updateDynamicList(); /// - void addComDerivatives( const int& , const Vector& , CatomPack& ); + void addComDerivatives( const int&, const Vector&, CatomPack& ); /// MultiValue& getUnderlyingMultiValue(); }; inline -void AtomValuePack::setNumberOfAtoms( const unsigned& nat ){ +void AtomValuePack::setNumberOfAtoms( const unsigned& nat ) { natoms=nat; } @@ -111,17 +111,17 @@ unsigned AtomValuePack::getNumberOfDerivatives() const { } inline -void AtomValuePack::setIndex( const unsigned& j, const unsigned& ind ){ - plumed_dbg_assert( j<natoms ); indices[j]=ind; +void AtomValuePack::setIndex( const unsigned& j, const unsigned& ind ) { + plumed_dbg_assert( j<natoms ); indices[j]=ind; } inline -void AtomValuePack::setAtomIndex( const unsigned& j, const unsigned& ind ){ +void AtomValuePack::setAtomIndex( const unsigned& j, const unsigned& ind ) { plumed_dbg_assert( j<natoms ); indices[j]=ind; } inline -void AtomValuePack::setAtom( const unsigned& j, const unsigned& ind ){ +void AtomValuePack::setAtom( const unsigned& j, const unsigned& ind ) { setAtomIndex( j, ind ); myatoms[j]=mycolv->getPositionOfAtomForLinkCells( ind ); } @@ -131,18 +131,18 @@ unsigned AtomValuePack::getIndex( const unsigned& j ) const { } inline -Vector& AtomValuePack::getPosition( const unsigned& iatom ){ +Vector& AtomValuePack::getPosition( const unsigned& iatom ) { plumed_dbg_assert( iatom<natoms ); - return myatoms[iatom]; + return myatoms[iatom]; } inline -void AtomValuePack::setValue( const unsigned& ival, const double& vv ){ +void AtomValuePack::setValue( const unsigned& ival, const double& vv ) { myvals.setValue( ival, vv ); } inline -void AtomValuePack::addValue( const unsigned& ival, const double& vv ){ +void AtomValuePack::addValue( const unsigned& ival, const double& vv ) { myvals.addValue( ival, vv ); } @@ -152,12 +152,12 @@ double AtomValuePack::getValue( const unsigned& ival ) const { } inline -void AtomValuePack::addDerivative( const unsigned& ival, const unsigned& jder, const double& der ){ - myvals.addDerivative( ival, jder, der ); +void AtomValuePack::addDerivative( const unsigned& ival, const unsigned& jder, const double& der ) { + myvals.addDerivative( ival, jder, der ); } inline -void AtomValuePack::addAtomsDerivatives( const unsigned& ival, const unsigned& jder, const Vector& der ){ +void AtomValuePack::addAtomsDerivatives( const unsigned& ival, const unsigned& jder, const Vector& der ) { plumed_dbg_assert( jder<natoms ); myvals.addDerivative( ival, 3*indices[jder] + 0, der[0] ); myvals.addDerivative( ival, 3*indices[jder] + 1, der[1] ); @@ -165,7 +165,7 @@ void AtomValuePack::addAtomsDerivatives( const unsigned& ival, const unsigned& j } inline -void AtomValuePack::addTemporyAtomsDerivatives( const unsigned& jder, const Vector& der ){ +void AtomValuePack::addTemporyAtomsDerivatives( const unsigned& jder, const Vector& der ) { plumed_dbg_assert( jder<natoms ); myvals.addTemporyDerivative( 3*indices[jder] + 0, der[0] ); myvals.addTemporyDerivative( 3*indices[jder] + 1, der[1] ); @@ -173,27 +173,27 @@ void AtomValuePack::addTemporyAtomsDerivatives( const unsigned& jder, const Vect } inline -void AtomValuePack::addTemporyBoxDerivatives( const Tensor& vir ){ +void AtomValuePack::addTemporyBoxDerivatives( const Tensor& vir ) { unsigned nvir=3*mycolv->getNumberOfAtoms(); - for(unsigned i=0;i<3;++i) for(unsigned j=0;j<3;++j) myvals.addTemporyDerivative( nvir + 3*i+j, vir(i,j) ); + for(unsigned i=0; i<3; ++i) for(unsigned j=0; j<3; ++j) myvals.addTemporyDerivative( nvir + 3*i+j, vir(i,j) ); } inline -void AtomValuePack::addBoxDerivatives( const unsigned& ival , const Tensor& vir ){ +void AtomValuePack::addBoxDerivatives( const unsigned& ival, const Tensor& vir ) { unsigned nvir=3*mycolv->getNumberOfAtoms(); - for(unsigned i=0;i<3;++i) for(unsigned j=0;j<3;++j) myvals.addDerivative( ival, nvir + 3*i+j, vir(i,j) ); + for(unsigned i=0; i<3; ++i) for(unsigned j=0; j<3; ++j) myvals.addDerivative( ival, nvir + 3*i+j, vir(i,j) ); } inline -void AtomValuePack::updateDynamicList(){ +void AtomValuePack::updateDynamicList() { if( myvals.updateComplete() ) return; myvals.updateDynamicList(); } inline -MultiValue& AtomValuePack::getUnderlyingMultiValue(){ +MultiValue& AtomValuePack::getUnderlyingMultiValue() { return myvals; -} +} } } diff --git a/src/multicolvar/Bridge.cpp b/src/multicolvar/Bridge.cpp index e56ec84d1..42198ffa1 100644 --- a/src/multicolvar/Bridge.cpp +++ b/src/multicolvar/Bridge.cpp @@ -29,10 +29,10 @@ using namespace std; -namespace PLMD{ -namespace multicolvar{ +namespace PLMD { +namespace multicolvar { -//+PLUMEDOC MCOLVAR BRIDGE +//+PLUMEDOC MCOLVAR BRIDGE /* Calculate the number of atoms that bridge two parts of a structure @@ -40,20 +40,20 @@ This quantity calculates: \f[ f(x) = \sum_{ijk} s_A(r_{ij})s_B(r_{ik}) -\f] +\f] -where the sum over \f$i\f$ is over all the ``bridging atoms" and +where the sum over \f$i\f$ is over all the ``bridging atoms" and \f$s_A\f$ and \f$s_B\f$ are \ref switchingfunction. \par Examples The following example instructs plumed to calculate the number of water molecules -that are bridging betweeen atoms 1-10 and atoms 11-20 and to print the value +that are bridging betweeen atoms 1-10 and atoms 11-20 and to print the value to a file \verbatim BRIDGE BRIDGING_ATOMS=100-200 GROUPA=1-10 GROUPB=11-20 LABEL=w1 -PRINT ARG=a1.mean FILE=colvar +PRINT ARG=a1.mean FILE=colvar \endverbatim */ @@ -69,27 +69,27 @@ public: explicit Bridge(const ActionOptions&); // active methods: virtual double compute( const unsigned& tindex, AtomValuePack& myatoms ) const ; - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } }; PLUMED_REGISTER_ACTION(Bridge,"BRIDGE") -void Bridge::registerKeywords( Keywords& keys ){ +void Bridge::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); keys.add("atoms-2","BRIDGING_ATOMS","The list of atoms that can form the bridge between the two interesting parts " - "of the structure."); - keys.add("atoms-2","GROUPA","The list of atoms that are in the first interesting part of the structure"); - keys.add("atoms-2","GROUPB","The list of atoms that are in the second interesting part of the structure"); + "of the structure."); + keys.add("atoms-2","GROUPA","The list of atoms that are in the first interesting part of the structure"); + keys.add("atoms-2","GROUPB","The list of atoms that are in the second interesting part of the structure"); keys.add("optional","SWITCH","The parameters of the two \\ref switchingfunction in the above formula"); keys.add("optional","SWITCHA","The \\ref switchingfunction on the distance between bridging atoms and the atoms in " - "group A"); + "group A"); keys.add("optional","SWITCHB","The \\ref switchingfunction on the distance between the bridging atoms and the atoms in " - "group B"); + "group B"); } Bridge::Bridge(const ActionOptions&ao): -Action(ao), -MultiColvarBase(ao) + Action(ao), + MultiColvarBase(ao) { // Read in the atoms std::vector<AtomNumber> all_atoms; @@ -98,27 +98,27 @@ MultiColvarBase(ao) setupMultiColvarBase( all_atoms ); // Setup Central atom atoms std::vector<bool> catom_ind(3, false); catom_ind[0]=true; - setAtomsForCentralAtom( catom_ind ); + setAtomsForCentralAtom( catom_ind ); std::string sfinput,errors; parse("SWITCH",sfinput); - if( sfinput.length()>0 ){ + if( sfinput.length()>0 ) { + sf1.set(sfinput,errors); + if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); + sf2.set(sfinput,errors); + if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); + } else { + parse("SWITCHA",sfinput); + if(sfinput.length()>0) { + weightHasDerivatives=true; sf1.set(sfinput,errors); - if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); + if( errors.length()!=0 ) error("problem reading SWITCHA keyword : " + errors ); + sfinput.clear(); parse("SWITCHB",sfinput); + if(sfinput.length()==0) error("found SWITCHA keyword without SWITCHB"); sf2.set(sfinput,errors); - if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); - } else { - parse("SWITCHA",sfinput); - if(sfinput.length()>0){ - weightHasDerivatives=true; - sf1.set(sfinput,errors); - if( errors.length()!=0 ) error("problem reading SWITCHA keyword : " + errors ); - sfinput.clear(); parse("SWITCHB",sfinput); - if(sfinput.length()==0) error("found SWITCHA keyword without SWITCHB"); - sf2.set(sfinput,errors); - if( errors.length()!=0 ) error("problem reading SWITCHB keyword : " + errors ); - } else { - error("missing definition of switching functions"); - } + if( errors.length()!=0 ) error("problem reading SWITCHB keyword : " + errors ); + } else { + error("missing definition of switching functions"); + } } log.printf(" distance between bridging atoms and atoms in GROUPA must be less than %s\n",sf1.description().c_str()); log.printf(" distance between bridging atoms and atoms in GROUPB must be less than %s\n",sf2.description().c_str()); @@ -137,18 +137,18 @@ MultiColvarBase(ao) double Bridge::compute( const unsigned& tindex, AtomValuePack& myatoms ) const { double tot=0; - for(unsigned i=2;i<myatoms.getNumberOfAtoms();++i){ - Vector dij=getSeparation( myatoms.getPosition(i), myatoms.getPosition(0) ); - double dw1, w1=sf1.calculateSqr( dij.modulo2(), dw1 ); - Vector dik=getSeparation( myatoms.getPosition(i), myatoms.getPosition(1) ); - double dw2, w2=sf2.calculateSqr( dik.modulo2(), dw2 ); - - tot += w1*w2; - // And finish the calculation - addAtomDerivatives( 1, 0, w2*dw1*dij, myatoms ); - addAtomDerivatives( 1, 1, w1*dw2*dik, myatoms ); - addAtomDerivatives( 1, i, -w1*dw2*dik-w2*dw1*dij, myatoms ); - myatoms.addBoxDerivatives( 1, w1*(-dw2)*Tensor(dik,dik)+w2*(-dw1)*Tensor(dij,dij) ); + for(unsigned i=2; i<myatoms.getNumberOfAtoms(); ++i) { + Vector dij=getSeparation( myatoms.getPosition(i), myatoms.getPosition(0) ); + double dw1, w1=sf1.calculateSqr( dij.modulo2(), dw1 ); + Vector dik=getSeparation( myatoms.getPosition(i), myatoms.getPosition(1) ); + double dw2, w2=sf2.calculateSqr( dik.modulo2(), dw2 ); + + tot += w1*w2; + // And finish the calculation + addAtomDerivatives( 1, 0, w2*dw1*dij, myatoms ); + addAtomDerivatives( 1, 1, w1*dw2*dik, myatoms ); + addAtomDerivatives( 1, i, -w1*dw2*dik-w2*dw1*dij, myatoms ); + myatoms.addBoxDerivatives( 1, w1*(-dw2)*Tensor(dik,dik)+w2*(-dw1)*Tensor(dij,dij) ); } return tot; } diff --git a/src/multicolvar/BridgedMultiColvarFunction.cpp b/src/multicolvar/BridgedMultiColvarFunction.cpp index 2087c0e71..435826e16 100644 --- a/src/multicolvar/BridgedMultiColvarFunction.cpp +++ b/src/multicolvar/BridgedMultiColvarFunction.cpp @@ -27,14 +27,14 @@ namespace PLMD { namespace multicolvar { -void BridgedMultiColvarFunction::registerKeywords( Keywords& keys ){ +void BridgedMultiColvarFunction::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); keys.add("compulsory","DATA","The multicolvar that calculates the set of base quantities that we are interested in"); } BridgedMultiColvarFunction::BridgedMultiColvarFunction(const ActionOptions&ao): -Action(ao), -MultiColvarBase(ao) + Action(ao), + MultiColvarBase(ao) { std::string mlab; parse("DATA",mlab); mycolv = plumed.getActionSet().selectWithLabel<MultiColvarBase*>(mlab); @@ -47,12 +47,12 @@ MultiColvarBase(ao) myBridgeVessel = mycolv->addBridgingVessel( this ); addDependency(mycolv); weightHasDerivatives=true; usespecies=mycolv->usespecies; // Number of tasks is the same as the number in the underlying MultiColvar - for(unsigned i=0;i<mycolv->getFullNumberOfTasks();++i) addTaskToList( mycolv->getTaskCode(i) ); + for(unsigned i=0; i<mycolv->getFullNumberOfTasks(); ++i) addTaskToList( mycolv->getTaskCode(i) ); } -void BridgedMultiColvarFunction::turnOnDerivatives(){ +void BridgedMultiColvarFunction::turnOnDerivatives() { BridgedMultiColvarFunction* check = dynamic_cast<BridgedMultiColvarFunction*>( mycolv ); - if( check ){ + if( check ) { if( check->getNumberOfAtoms()>0 ) error("cannot calculate required derivatives of this quantity"); } MultiColvarBase::turnOnDerivatives(); @@ -60,18 +60,18 @@ void BridgedMultiColvarFunction::turnOnDerivatives(){ void BridgedMultiColvarFunction::transformBridgedDerivatives( const unsigned& current, MultiValue& invals, MultiValue& outvals ) const { completeTask( current, invals, outvals ); - + // Now update the outvals derivatives lists - if( derivativesAreRequired() ){ - outvals.emptyActiveMembers(); - if( mycolv->isDensity() ){ - for(unsigned j=0;j<3;++j) outvals.putIndexInActiveArray( 3*current+j ); - for(unsigned j=invals.getNumberOfDerivatives()-9;j<invals.getNumberOfDerivatives();++j) outvals.putIndexInActiveArray(j); - } else { - for(unsigned j=0;j<invals.getNumberActive();++j) outvals.putIndexInActiveArray( invals.getActiveIndex(j) ); - } - for(unsigned j=invals.getNumberOfDerivatives();j<outvals.getNumberOfDerivatives();++j) outvals.putIndexInActiveArray( j ); - outvals.completeUpdate(); + if( derivativesAreRequired() ) { + outvals.emptyActiveMembers(); + if( mycolv->isDensity() ) { + for(unsigned j=0; j<3; ++j) outvals.putIndexInActiveArray( 3*current+j ); + for(unsigned j=invals.getNumberOfDerivatives()-9; j<invals.getNumberOfDerivatives(); ++j) outvals.putIndexInActiveArray(j); + } else { + for(unsigned j=0; j<invals.getNumberActive(); ++j) outvals.putIndexInActiveArray( invals.getActiveIndex(j) ); + } + for(unsigned j=invals.getNumberOfDerivatives(); j<outvals.getNumberOfDerivatives(); ++j) outvals.putIndexInActiveArray( j ); + outvals.completeUpdate(); } } @@ -79,43 +79,43 @@ void BridgedMultiColvarFunction::performTask( const unsigned& taskIndex, const u // This allows us to speed up the code as we don't need to reallocate memory on every call of perform task MultiValue& invals=myBridgeVessel->getTemporyMultiValue(); if( invals.getNumberOfValues()!=mycolv->getNumberOfQuantities() || - invals.getNumberOfDerivatives()!=mycolv->getNumberOfDerivatives() ){ - invals.resize( mycolv->getNumberOfQuantities(), mycolv->getNumberOfDerivatives() ); + invals.getNumberOfDerivatives()!=mycolv->getNumberOfDerivatives() ) { + invals.resize( mycolv->getNumberOfQuantities(), mycolv->getNumberOfDerivatives() ); } invals.clearAll(); mycolv->performTask( taskIndex, current, invals ); - transformBridgedDerivatives( taskIndex, invals, myvals ); + transformBridgedDerivatives( taskIndex, invals, myvals ); } -void BridgedMultiColvarFunction::calculateNumericalDerivatives( ActionWithValue* a ){ - if(!a){ +void BridgedMultiColvarFunction::calculateNumericalDerivatives( ActionWithValue* a ) { + if(!a) { a=dynamic_cast<ActionWithValue*>(this); plumed_massert(a,"cannot compute numerical derivatives for an action without values"); } - if( myBridgeVessel ){ - myBridgeVessel->completeNumericalDerivatives(); + if( myBridgeVessel ) { + myBridgeVessel->completeNumericalDerivatives(); } else { - error("numerical derivatives are not implemented"); + error("numerical derivatives are not implemented"); } } -void BridgedMultiColvarFunction::applyBridgeForces( const std::vector<double>& bb ){ +void BridgedMultiColvarFunction::applyBridgeForces( const std::vector<double>& bb ) { if( getNumberOfAtoms()==0 ) return ; std::vector<Vector>& f( modifyForces() ); - for(unsigned i=0;i<getNumberOfAtoms();++i){ + for(unsigned i=0; i<getNumberOfAtoms(); ++i) { f[i][0]+=bb[3*i+0]; f[i][1]+=bb[3*i+1]; f[i][2]+=bb[3*i+2]; - } + } } -bool BridgedMultiColvarFunction::isPeriodic(){ +bool BridgedMultiColvarFunction::isPeriodic() { return mycolv->isPeriodic(); } -void BridgedMultiColvarFunction::deactivate_task( const unsigned& taskno ){ +void BridgedMultiColvarFunction::deactivate_task( const unsigned& taskno ) { plumed_merror("This should never be called"); } -void BridgedMultiColvarFunction::getCentralAtomPack( const unsigned& basn, const unsigned& curr, CatomPack& mypack ){ +void BridgedMultiColvarFunction::getCentralAtomPack( const unsigned& basn, const unsigned& curr, CatomPack& mypack ) { return mycolv->getCentralAtomPack( basn, curr, mypack ); } diff --git a/src/multicolvar/BridgedMultiColvarFunction.h b/src/multicolvar/BridgedMultiColvarFunction.h index 216bd52a1..b23ccb906 100644 --- a/src/multicolvar/BridgedMultiColvarFunction.h +++ b/src/multicolvar/BridgedMultiColvarFunction.h @@ -29,8 +29,8 @@ namespace PLMD { namespace multicolvar { class BridgedMultiColvarFunction : public MultiColvarBase { -friend class MultiColvarBase; -friend class MultiColvarFunction; + friend class MultiColvarBase; + friend class MultiColvarFunction; private: /// This is used for storing positions properly Vector tmp_p; @@ -51,23 +51,23 @@ public: explicit BridgedMultiColvarFunction(const ActionOptions&); /// Get a pointer to the base multicolvar MultiColvarBase* getPntrToMultiColvar() const ; -/// Don't actually clear the derivatives when this is called from plumed main. -/// They are calculated inside another action and clearing them would be bad - void clearDerivatives(){} +/// Don't actually clear the derivatives when this is called from plumed main. +/// They are calculated inside another action and clearing them would be bad + void clearDerivatives() {} /// Check nothing impossible being done with derivatives virtual void turnOnDerivatives(); /// Get the number of derivatives for this action - unsigned getNumberOfDerivatives(); + unsigned getNumberOfDerivatives(); /// Get the size of the atoms with derivatives array unsigned getSizeOfAtomsWithDerivatives(); /// Is the output quantity periodic bool isPeriodic(); -/// Routines that have to be defined so as not to have problems with virtual methods +/// Routines that have to be defined so as not to have problems with virtual methods void deactivate_task( const unsigned& taskno ); - void calculate(){} + void calculate() {} /// This does the task void transformBridgedDerivatives( const unsigned& current, MultiValue& invals, MultiValue& outvals ) const ; - void performTask( const unsigned& , const unsigned& , MultiValue& ) const ; + void performTask( const unsigned&, const unsigned&, MultiValue& ) const ; virtual void completeTask( const unsigned& curr, MultiValue& invals, MultiValue& outvals ) const=0; /// Get the central atom position Vector retrieveCentralAtomPos(); @@ -77,11 +77,11 @@ public: const std::vector<AtomNumber> & getAbsoluteIndexes()const ; /// We need our own calculate numerical derivatives here void calculateNumericalDerivatives( ActionWithValue* a=NULL ); - void apply(){}; -/// Is this atom currently being copied + void apply() {}; +/// Is this atom currently being copied bool isCurrentlyActive( const unsigned& ); /// This should not be called - Vector calculateCentralAtomPosition(){ plumed_error(); } + Vector calculateCentralAtomPosition() { plumed_error(); } double compute( const unsigned& tindex, AtomValuePack& myvals ) const { plumed_error(); } Vector getPositionOfAtomForLinkCells( const unsigned& iatom ) const ; void getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices ); @@ -103,33 +103,33 @@ MultiColvarBase* BridgedMultiColvarFunction::getPntrToMultiColvar() const { } inline -unsigned BridgedMultiColvarFunction::getNumberOfDerivatives(){ +unsigned BridgedMultiColvarFunction::getNumberOfDerivatives() { return mycolv->getNumberOfDerivatives() + 3*getNumberOfAtoms(); } inline -bool BridgedMultiColvarFunction::isCurrentlyActive( const unsigned& code ){ +bool BridgedMultiColvarFunction::isCurrentlyActive( const unsigned& code ) { return mycolv->isCurrentlyActive( code ); } inline -unsigned BridgedMultiColvarFunction::getSizeOfAtomsWithDerivatives(){ +unsigned BridgedMultiColvarFunction::getSizeOfAtomsWithDerivatives() { return mycolv->getNumberOfAtoms(); } -inline -Vector BridgedMultiColvarFunction::getPositionOfAtomForLinkCells( const unsigned& iatom ) const { +inline +Vector BridgedMultiColvarFunction::getPositionOfAtomForLinkCells( const unsigned& iatom ) const { return mycolv->getPositionOfAtomForLinkCells(iatom); } inline -Vector BridgedMultiColvarFunction::getCentralAtomPos( const unsigned& curr ){ +Vector BridgedMultiColvarFunction::getCentralAtomPos( const unsigned& curr ) { return mycolv->getCentralAtomPos( curr ); } inline AtomNumber BridgedMultiColvarFunction::getAbsoluteIndexOfCentralAtom(const unsigned& i) const { - return mycolv->getAbsoluteIndexOfCentralAtom(i); + return mycolv->getAbsoluteIndexOfCentralAtom(i); } inline diff --git a/src/multicolvar/CatomPack.cpp b/src/multicolvar/CatomPack.cpp index 59e1d8e44..900fa5e70 100644 --- a/src/multicolvar/CatomPack.cpp +++ b/src/multicolvar/CatomPack.cpp @@ -21,10 +21,10 @@ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ #include "CatomPack.h" -namespace PLMD{ -namespace multicolvar{ +namespace PLMD { +namespace multicolvar { -void CatomPack::resize( const unsigned& size ){ +void CatomPack::resize( const unsigned& size ) { indices.resize(size); derivs.resize(size); } diff --git a/src/multicolvar/CatomPack.h b/src/multicolvar/CatomPack.h index e960d3db5..130e971cd 100644 --- a/src/multicolvar/CatomPack.h +++ b/src/multicolvar/CatomPack.h @@ -36,24 +36,24 @@ private: std::vector<Tensor> derivs; public: void resize( const unsigned& ); - void setIndex( const unsigned& , const unsigned& ); - void setDerivative( const unsigned& , const Tensor& ); + void setIndex( const unsigned&, const unsigned& ); + void setDerivative( const unsigned&, const Tensor& ); unsigned getNumberOfAtomsWithDerivatives() const ; unsigned getIndex( const unsigned& ) const ; - double getDerivative( const unsigned&, const unsigned& , const Vector& ) const ; + double getDerivative( const unsigned&, const unsigned&, const Vector& ) const ; }; inline -void CatomPack::setIndex( const unsigned& jind, const unsigned& ind ){ +void CatomPack::setIndex( const unsigned& jind, const unsigned& ind ) { plumed_dbg_assert( jind<indices.size() ); indices[jind]=ind; } inline -void CatomPack::setDerivative( const unsigned& jind , const Tensor& der ){ +void CatomPack::setDerivative( const unsigned& jind, const Tensor& der ) { plumed_dbg_assert( jind<indices.size() ); derivs[jind]=der; -} +} inline unsigned CatomPack::getNumberOfAtomsWithDerivatives() const { @@ -75,4 +75,4 @@ double CatomPack::getDerivative( const unsigned& iatom, const unsigned& jcomp, c } } -#endif +#endif diff --git a/src/multicolvar/CenterOfMultiColvar.cpp b/src/multicolvar/CenterOfMultiColvar.cpp index 9b765f957..f8b5be660 100644 --- a/src/multicolvar/CenterOfMultiColvar.cpp +++ b/src/multicolvar/CenterOfMultiColvar.cpp @@ -40,15 +40,15 @@ This action calculates the position of a new virtual atom using the following fo x_\alpha = \frac{1}{2\pi} \arctan \left[ \frac{ \sum_i w_i f_i \sin\left( 2\pi x_{i,\alpha} \right) }{ \sum_i w_i f_i \cos\left( 2\pi x_{i,\alpha} \right) } \right] \f] -Where in this expression the \f$w_i\f$ values are a set of weights calculated within a multicolvar -action and the \f$f_i\f$ are the values of the multicolvar functions. The \f$x_{i,\alpha}\f$ values are -the positions (in scaled coordinates) associated with each of the multicolvars calculated. +Where in this expression the \f$w_i\f$ values are a set of weights calculated within a multicolvar +action and the \f$f_i\f$ are the values of the multicolvar functions. The \f$x_{i,\alpha}\f$ values are +the positions (in scaled coordinates) associated with each of the multicolvars calculated. \bug The virial contribution for this type of virtual atom is not currently evaluated so do not use in bias functions unless the volume of the cell is fixed \par Examples -Lets suppose that you are examining the formation of liquid droplets from gas. You may want to +Lets suppose that you are examining the formation of liquid droplets from gas. You may want to determine the center of mass of any of the droplets formed. In doing this calculation you recognise that the atoms in the liquid droplets will have a higher coordination number than those in the surrounding gas. As you want to calculate the position of the droplets you thus recognise that these atoms with high coordination @@ -61,26 +61,26 @@ cc: CENTER_OF_MULTICOLVAR DATA=c1 \endverbatim The first line here calclates the coordination numbers of all the atoms in the system. The virtual atom then uses the values -of the coordination numbers calculated by the action labelled c1 when it calculates the Berry Phase average described above. +of the coordination numbers calculated by the action labelled c1 when it calculates the Berry Phase average described above. (N.B. the \f$w_i\f$ in the above expression are all set equal to 1 in this case) The above input is fine we can, however, refine this somewhat by making use of a multicolvar transform action as shown below: -\verbatim +\verbatim c1: COORDINATIONNUMBER SPECIES=1-512 SWITCH={EXP D_0=4.0 R_0=0.5} cf: MTRANSFORM_MORE DATA=c1 SWITCH={RATIONAL D_0=2.0 R_0=0.1} LOWMEM cc: CENTER_OF_MULTICOLVAR DATA=cf \endverbatim This input once again calculates the coordination numbers of all the atoms in the system. The middle line then transforms these -coordinations numbers to numbers between 0 and 1. Essentially any atom with a coordination number larger than 2.0 is given a weight +coordinations numbers to numbers between 0 and 1. Essentially any atom with a coordination number larger than 2.0 is given a weight of one and below this value the transformed value decays to zero. It is these transformed coordination numbers that are used to calculate the Berry phase average described in the previous section. */ //+ENDPLUMEDOC -namespace PLMD{ +namespace PLMD { namespace multicolvar { @@ -97,7 +97,7 @@ public: PLUMED_REGISTER_ACTION(CenterOfMultiColvar,"CENTER_OF_MULTICOLVAR") -void CenterOfMultiColvar::registerKeywords(Keywords& keys){ +void CenterOfMultiColvar::registerKeywords(Keywords& keys) { ActionWithVirtualAtom::registerKeywords(keys); keys.add("compulsory","DATA","find the average value for a multicolvar"); keys.add("optional","COMPONENT","if your input multicolvar is a vector then specify which component you would like to use in calculating the weight"); @@ -112,108 +112,108 @@ CenterOfMultiColvar::CenterOfMultiColvar(const ActionOptions&ao): if(!mycolv) error("action labelled " + mlab + " does not exist or does not have vessels"); // Copy the atoms from the input multicolvar BridgedMultiColvarFunction* mybr=dynamic_cast<BridgedMultiColvarFunction*>( mycolv ); - if( mybr ){ - requestAtoms( (mybr->getPntrToMultiColvar())->getAbsoluteIndexes() ); comp=1; - } else { - if( mycolv->getNumberOfQuantities()>5 ){ - int incomp=-1; parse("COMPONENT",incomp); - if( incomp<0 ) error("vector input but component was not specified"); - comp=incomp; - } else { - comp=1; - } - requestAtoms( mycolv->getAbsoluteIndexes () ); + if( mybr ) { + requestAtoms( (mybr->getPntrToMultiColvar())->getAbsoluteIndexes() ); comp=1; + } else { + if( mycolv->getNumberOfQuantities()>5 ) { + int incomp=-1; parse("COMPONENT",incomp); + if( incomp<0 ) error("vector input but component was not specified"); + comp=incomp; + } else { + comp=1; + } + requestAtoms( mycolv->getAbsoluteIndexes () ); } // We need the derivatives - mycolv->turnOnDerivatives(); addDependency(mycolv); + mycolv->turnOnDerivatives(); addDependency(mycolv); mystash = mycolv->buildDataStashes( NULL ); log.printf(" building center of mass based on weights calculated in multicolvar action named %s \n",mycolv->getLabel().c_str() ); } -void CenterOfMultiColvar::calculate(){ +void CenterOfMultiColvar::calculate() { // Retrieve the periodic boundary conditions const Pbc& pbc=mycolv->getPbc(); - if( !pbc.isOrthorombic() ) error("Berry phase does not work for non orthorhombic cells"); - + if( !pbc.isOrthorombic() ) error("Berry phase does not work for non orthorhombic cells"); + // Create a multivalue to store the derivatives MultiValue myvals( 7, mycolv->getNumberOfDerivatives() ); myvals.clearAll(); MultiValue tvals( mycolv->getNumberOfQuantities(), mycolv->getNumberOfDerivatives() ); tvals.clearAll(); - // Now loop over all active multicolvars - Vector stmp, ctmp, scom, ccom, sder, cder; + // Now loop over all active multicolvars + Vector stmp, ctmp, scom, ccom, sder, cder; scom.zero(); ccom.zero(); double norm=0; std::vector<double> cvals( mycolv->getNumberOfQuantities() ); - for(unsigned i=0;i<mystash->getNumberOfStoredValues();++i){ - // Retrieve value and derivatives - mystash->retrieveSequentialValue( i, false, cvals ); - mystash->retrieveDerivatives( mycolv->getPositionInFullTaskList(i), false, tvals ); - // Convert position into fractionals - Vector fpos = pbc.realToScaled( mycolv->getCentralAtomPos( mycolv->getPositionInFullTaskList(i) ) ); - // Now accumulate Berry phase averages - for(unsigned j=0;j<3;++j){ - stmp[j] = sin( 2*pi*fpos[j] ); ctmp[j] = cos( 2*pi*fpos[j] ); - scom[j] += cvals[0]*cvals[comp]*stmp[j]; ccom[j] += cvals[0]*cvals[comp]*ctmp[j]; - double icell = 1.0 / getPbc().getBox().getRow(j).modulo(); - sder[j] = 2*pi*icell*cvals[0]*cvals[comp]*cos( 2*pi*fpos[j] ); - cder[j]=-2*pi*icell*cvals[0]*cvals[comp]*sin( 2*pi*fpos[j] ); - } - // Now accumulate derivatives - for(unsigned k=0;k<tvals.getNumberActive();++k){ - unsigned icomp=tvals.getActiveIndex(k); - myvals.addDerivative( 0, icomp, cvals[0]*tvals.getDerivative( comp, icomp ) + cvals[comp]*tvals.getDerivative( 0, icomp ) ); - for(unsigned k=0;k<3;++k){ - myvals.addDerivative( 1+k, icomp, stmp[k]*( cvals[0]*tvals.getDerivative( comp, icomp ) + - cvals[comp]*tvals.getDerivative( 0, icomp ) ) ); - myvals.addDerivative( 4+k, icomp, ctmp[k]*( cvals[0]*tvals.getDerivative( comp, icomp ) + - cvals[comp]*tvals.getDerivative( 0, icomp ) ) ); - } + for(unsigned i=0; i<mystash->getNumberOfStoredValues(); ++i) { + // Retrieve value and derivatives + mystash->retrieveSequentialValue( i, false, cvals ); + mystash->retrieveDerivatives( mycolv->getPositionInFullTaskList(i), false, tvals ); + // Convert position into fractionals + Vector fpos = pbc.realToScaled( mycolv->getCentralAtomPos( mycolv->getPositionInFullTaskList(i) ) ); + // Now accumulate Berry phase averages + for(unsigned j=0; j<3; ++j) { + stmp[j] = sin( 2*pi*fpos[j] ); ctmp[j] = cos( 2*pi*fpos[j] ); + scom[j] += cvals[0]*cvals[comp]*stmp[j]; ccom[j] += cvals[0]*cvals[comp]*ctmp[j]; + double icell = 1.0 / getPbc().getBox().getRow(j).modulo(); + sder[j] = 2*pi*icell*cvals[0]*cvals[comp]*cos( 2*pi*fpos[j] ); + cder[j]=-2*pi*icell*cvals[0]*cvals[comp]*sin( 2*pi*fpos[j] ); + } + // Now accumulate derivatives + for(unsigned k=0; k<tvals.getNumberActive(); ++k) { + unsigned icomp=tvals.getActiveIndex(k); + myvals.addDerivative( 0, icomp, cvals[0]*tvals.getDerivative( comp, icomp ) + cvals[comp]*tvals.getDerivative( 0, icomp ) ); + for(unsigned k=0; k<3; ++k) { + myvals.addDerivative( 1+k, icomp, stmp[k]*( cvals[0]*tvals.getDerivative( comp, icomp ) + + cvals[comp]*tvals.getDerivative( 0, icomp ) ) ); + myvals.addDerivative( 4+k, icomp, ctmp[k]*( cvals[0]*tvals.getDerivative( comp, icomp ) + + cvals[comp]*tvals.getDerivative( 0, icomp ) ) ); } - // Get the central atom pack - CatomPack mypack; mycolv->getCentralAtomPack( 0, mycolv->getPositionInFullTaskList(i), mypack ); - for(unsigned j=0;j<mypack.getNumberOfAtomsWithDerivatives();++j){ - unsigned jder=3*mypack.getIndex(j); - // Derivatives of sine - myvals.addDerivative( 1, jder+0, mypack.getDerivative(j, 0, sder) ); - myvals.addDerivative( 2, jder+1, mypack.getDerivative(j, 1, sder) ); - myvals.addDerivative( 3, jder+2, mypack.getDerivative(j, 2, sder) ); - // Derivatives of cosine - myvals.addDerivative( 4, jder+0, mypack.getDerivative(j, 0, cder) ); - myvals.addDerivative( 5, jder+1, mypack.getDerivative(j, 1, cder) ); - myvals.addDerivative( 6, jder+2, mypack.getDerivative(j, 2, cder) ); - } - norm += cvals[0]*cvals[comp]; tvals.clearAll(); + } + // Get the central atom pack + CatomPack mypack; mycolv->getCentralAtomPack( 0, mycolv->getPositionInFullTaskList(i), mypack ); + for(unsigned j=0; j<mypack.getNumberOfAtomsWithDerivatives(); ++j) { + unsigned jder=3*mypack.getIndex(j); + // Derivatives of sine + myvals.addDerivative( 1, jder+0, mypack.getDerivative(j, 0, sder) ); + myvals.addDerivative( 2, jder+1, mypack.getDerivative(j, 1, sder) ); + myvals.addDerivative( 3, jder+2, mypack.getDerivative(j, 2, sder) ); + // Derivatives of cosine + myvals.addDerivative( 4, jder+0, mypack.getDerivative(j, 0, cder) ); + myvals.addDerivative( 5, jder+1, mypack.getDerivative(j, 1, cder) ); + myvals.addDerivative( 6, jder+2, mypack.getDerivative(j, 2, cder) ); + } + norm += cvals[0]*cvals[comp]; tvals.clearAll(); } // And now finish Berry phase average scom /= norm; ccom /=norm; Vector cpos; - for(unsigned j=0;j<3;++j) cpos[j] = atan2( scom[j], ccom[j] ) / (2*pi); + for(unsigned j=0; j<3; ++j) cpos[j] = atan2( scom[j], ccom[j] ) / (2*pi); Vector cart_pos = pbc.scaledToReal( cpos ); setPosition(cart_pos); setMass(1.0); // This could be much cleverer but not without changing many things in PLMED - - // And derivatives + + // And derivatives Vector tander; myvals.updateDynamicList(); double inv_weight = 1.0 / norm; - for(unsigned j=0;j<3;++j){ - double tmp = scom[j] / ccom[j]; - tander[j] = getPbc().getBox().getRow(j).modulo() / (2*pi*( 1 + tmp*tmp )); + for(unsigned j=0; j<3; ++j) { + double tmp = scom[j] / ccom[j]; + tander[j] = getPbc().getBox().getRow(j).modulo() / (2*pi*( 1 + tmp*tmp )); } - for(unsigned i=0;i<myvals.getNumberActive();++i){ - unsigned ider=myvals.getActiveIndex(i); - for(unsigned j=0;j<3;++j){ - double sderv = inv_weight*myvals.getDerivative(1+j,ider) - inv_weight*scom[j]*myvals.getDerivative(0,ider); - double cderv = inv_weight*myvals.getDerivative(4+j,ider) - inv_weight*ccom[j]*myvals.getDerivative(0,ider); - myvals.setDerivative( 1+j, ider, tander[j]*(sderv/ccom[j] - scom[j]*cderv/(ccom[j]*ccom[j])) ); - //if( j==2 ) printf("DERIV %d %10.4f %10.4f %10.4f %10.4f \n",i,myvals.getDerivative(0,ider),sderv,cderv,myvals.getDerivative(1+j,ider ) ); - } + for(unsigned i=0; i<myvals.getNumberActive(); ++i) { + unsigned ider=myvals.getActiveIndex(i); + for(unsigned j=0; j<3; ++j) { + double sderv = inv_weight*myvals.getDerivative(1+j,ider) - inv_weight*scom[j]*myvals.getDerivative(0,ider); + double cderv = inv_weight*myvals.getDerivative(4+j,ider) - inv_weight*ccom[j]*myvals.getDerivative(0,ider); + myvals.setDerivative( 1+j, ider, tander[j]*(sderv/ccom[j] - scom[j]*cderv/(ccom[j]*ccom[j])) ); + //if( j==2 ) printf("DERIV %d %10.4f %10.4f %10.4f %10.4f \n",i,myvals.getDerivative(0,ider),sderv,cderv,myvals.getDerivative(1+j,ider ) ); + } } // Atom derivatives std::vector<Tensor> fderiv( getNumberOfAtoms() ); - for(unsigned j=0;j<getNumberOfAtoms();++j){ - for(unsigned k=0;k<3;++k){ - if( myvals.isActive(3*j+k) ) for(unsigned n=0;n<3;++n) fderiv[j](k,n) = myvals.getDerivative( 1+n, 3*j+k ); - else for(unsigned n=0;n<3;++n) fderiv[j](k,n) = 0; - } + for(unsigned j=0; j<getNumberOfAtoms(); ++j) { + for(unsigned k=0; k<3; ++k) { + if( myvals.isActive(3*j+k) ) for(unsigned n=0; n<3; ++n) fderiv[j](k,n) = myvals.getDerivative( 1+n, 3*j+k ); + else for(unsigned n=0; n<3; ++n) fderiv[j](k,n) = 0; + } } setAtomsDerivatives( fderiv ); // Box derivatives? diff --git a/src/multicolvar/CoordinationNumbers.cpp b/src/multicolvar/CoordinationNumbers.cpp index 67ee34374..a3823b488 100644 --- a/src/multicolvar/CoordinationNumbers.cpp +++ b/src/multicolvar/CoordinationNumbers.cpp @@ -30,13 +30,13 @@ using namespace std; -namespace PLMD{ -namespace multicolvar{ +namespace PLMD { +namespace multicolvar { //+PLUMEDOC MCOLVAR COORDINATIONNUMBER /* Calculate the coordination numbers of atoms so that you can then calculate functions of the distribution of -coordination numbers such as the minimum, the number less than a certain quantity and so on. +coordination numbers such as the minimum, the number less than a certain quantity and so on. To make the calculation of coordination numbers differentiable the following function is used: @@ -53,7 +53,7 @@ COORDINATIONNUMBER SPECIES=1-100 R_0=1.0 MIN={BETA=0.1} \endverbatim The following input tells plumed to calculate how many atoms from 1-100 are within 3.0 of each of the atoms -from 101-110. In the first 101 is the central atom, in the second 102 is the central atom and so on. The +from 101-110. In the first 101 is the central atom, in the second 102 is the central atom and so on. The number of coordination numbers more than 6 is then computed. \verbatim COORDINATIONNUMBER SPECIESA=101-110 SPECIESB=1-100 R_0=3.0 MORE_THAN={RATIONAL R_0=6.0 NN=6 MM=12 D_0=0} @@ -72,14 +72,14 @@ public: static void registerKeywords( Keywords& keys ); explicit CoordinationNumbers(const ActionOptions&); // active methods: - virtual double compute( const unsigned& tindex, AtomValuePack& myatoms ) const ; + virtual double compute( const unsigned& tindex, AtomValuePack& myatoms ) const ; /// Returns the number of coordinates of the field - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } }; PLUMED_REGISTER_ACTION(CoordinationNumbers,"COORDINATIONNUMBER") -void CoordinationNumbers::registerKeywords( Keywords& keys ){ +void CoordinationNumbers::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); keys.use("SPECIES"); keys.use("SPECIESA"); keys.use("SPECIESB"); keys.add("compulsory","NN","6","The n parameter of the switching function "); @@ -87,29 +87,29 @@ void CoordinationNumbers::registerKeywords( Keywords& keys ){ keys.add("compulsory","D_0","0.0","The d_0 parameter of the switching function"); keys.add("compulsory","R_0","The r_0 parameter of the switching function"); keys.add("optional","SWITCH","This keyword is used if you want to employ an alternative to the continuous swiching function defined above. " - "The following provides information on the \\ref switchingfunction that are available. " - "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); + "The following provides information on the \\ref switchingfunction that are available. " + "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); // Use actionWithDistributionKeywords keys.use("MEAN"); keys.use("MORE_THAN"); keys.use("LESS_THAN"); keys.use("MAX"); keys.use("MIN"); keys.use("BETWEEN"); keys.use("HISTOGRAM"); keys.use("MOMENTS"); - keys.use("ALT_MIN"); keys.use("LOWEST"); keys.use("HIGHEST"); + keys.use("ALT_MIN"); keys.use("LOWEST"); keys.use("HIGHEST"); } CoordinationNumbers::CoordinationNumbers(const ActionOptions&ao): -Action(ao), -MultiColvarBase(ao) + Action(ao), + MultiColvarBase(ao) { // Read in the switching function std::string sw, errors; parse("SWITCH",sw); - if(sw.length()>0){ - switchingFunction.set(sw,errors); - if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); - } else { - double r_0=-1.0, d_0; int nn, mm; - parse("NN",nn); parse("MM",mm); - parse("R_0",r_0); parse("D_0",d_0); - if( r_0<0.0 ) error("you must set a value for R_0"); - switchingFunction.set(nn,mm,r_0,d_0); + if(sw.length()>0) { + switchingFunction.set(sw,errors); + if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); + } else { + double r_0=-1.0, d_0; int nn, mm; + parse("NN",nn); parse("MM",mm); + parse("R_0",r_0); parse("D_0",d_0); + if( r_0<0.0 ) error("you must set a value for R_0"); + switchingFunction.set(nn,mm,r_0,d_0); } log.printf(" coordination of central atom and those within %s\n",( switchingFunction.description() ).c_str() ); // Set the link cell cutoff @@ -121,20 +121,20 @@ MultiColvarBase(ao) } double CoordinationNumbers::compute( const unsigned& tindex, AtomValuePack& myatoms ) const { - // Calculate the coordination number - double dfunc, d2, sw; - for(unsigned i=1;i<myatoms.getNumberOfAtoms();++i){ - Vector& distance=myatoms.getPosition(i); - if ( (d2=distance[0]*distance[0])<rcut2 && - (d2+=distance[1]*distance[1])<rcut2 && - (d2+=distance[2]*distance[2])<rcut2) { - - sw = switchingFunction.calculateSqr( d2, dfunc ); - accumulateSymmetryFunction( 1, i, sw, (dfunc)*distance, (-dfunc)*Tensor(distance,distance), myatoms ); - } - } - - return myatoms.getValue(1); + // Calculate the coordination number + double dfunc, d2, sw; + for(unsigned i=1; i<myatoms.getNumberOfAtoms(); ++i) { + Vector& distance=myatoms.getPosition(i); + if ( (d2=distance[0]*distance[0])<rcut2 && + (d2+=distance[1]*distance[1])<rcut2 && + (d2+=distance[2]*distance[2])<rcut2) { + + sw = switchingFunction.calculateSqr( d2, dfunc ); + accumulateSymmetryFunction( 1, i, sw, (dfunc)*distance, (-dfunc)*Tensor(distance,distance), myatoms ); + } + } + + return myatoms.getValue(1); } } diff --git a/src/multicolvar/Density.cpp b/src/multicolvar/Density.cpp index 6ec23cedc..0351140a3 100644 --- a/src/multicolvar/Density.cpp +++ b/src/multicolvar/Density.cpp @@ -28,17 +28,17 @@ using namespace std; -namespace PLMD{ -namespace multicolvar{ +namespace PLMD { +namespace multicolvar { //+PLUMEDOC MCOLVAR DENSITY /* Calculate functions of the density of atoms as a function of the box. This allows one to calculate the number of atoms in half the box. -\par Examples +\par Examples -The following example calculates the number of atoms in one half of the simulation box. +The following example calculates the number of atoms in one half of the simulation box. \verbatim DENSITY SPECIES=1-100 LABEL=d @@ -57,10 +57,10 @@ public: // active methods: virtual double compute( const unsigned& tindex, AtomValuePack& myatoms ) const ; /// Returns the number of coordinates of the field - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } bool isDensity() const { return true; } bool hasDifferentiableOrientation() const { return true; } -// void addOrientationDerivativesToBase( const unsigned& iatom, const unsigned& jstore, const unsigned& base_cv_no, +// void addOrientationDerivativesToBase( const unsigned& iatom, const unsigned& jstore, const unsigned& base_cv_no, // const std::vector<double>& weight, MultiColvarFunction* func ){} void getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices ); // unsigned getNumberOfQuantities(); @@ -69,37 +69,37 @@ public: PLUMED_REGISTER_ACTION(Density,"DENSITY") -void Density::registerKeywords( Keywords& keys ){ +void Density::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); - keys.use("SPECIES"); + keys.use("SPECIES"); } Density::Density(const ActionOptions&ao): -Action(ao), -MultiColvarBase(ao) + Action(ao), + MultiColvarBase(ao) { std::vector<AtomNumber> all_atoms; parseMultiColvarAtomList("SPECIES", -1, all_atoms); - ablocks.resize(1); ablocks[0].resize( atom_lab.size() ); - for(unsigned i=0;i<atom_lab.size();++i){ addTaskToList(i); ablocks[0][i]=i; } + ablocks.resize(1); ablocks[0].resize( atom_lab.size() ); + for(unsigned i=0; i<atom_lab.size(); ++i) { addTaskToList(i); ablocks[0][i]=i; } setupMultiColvarBase( all_atoms ); // And check everything has been read in correctly - checkRead(); + checkRead(); } double Density::compute( const unsigned& tindex, AtomValuePack& myvals ) const { return 1.0; } -void Density::getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices ){ - indices[jstore]=0; +void Density::getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices ) { + indices[jstore]=0; } // unsigned Density::getNumberOfQuantities(){ // return 2; // } -void Density::getValueForTask( const unsigned& iatom, std::vector<double>& vals ){ - plumed_dbg_assert( vals.size()==2 ); vals[0]=vals[1]=1.0; +void Density::getValueForTask( const unsigned& iatom, std::vector<double>& vals ) { + plumed_dbg_assert( vals.size()==2 ); vals[0]=vals[1]=1.0; } } diff --git a/src/multicolvar/DihedralCorrelation.cpp b/src/multicolvar/DihedralCorrelation.cpp index fb5b644c4..e75bde668 100644 --- a/src/multicolvar/DihedralCorrelation.cpp +++ b/src/multicolvar/DihedralCorrelation.cpp @@ -29,8 +29,8 @@ using namespace std; -namespace PLMD{ -namespace multicolvar{ +namespace PLMD { +namespace multicolvar { //+PLUMEDOC COLVAR DIHCOR /* @@ -87,39 +87,39 @@ public: static void registerKeywords( Keywords& keys ); explicit DihedralCorrelation(const ActionOptions&); virtual double compute( const unsigned& tindex, AtomValuePack& myatoms ) const ; - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } }; PLUMED_REGISTER_ACTION(DihedralCorrelation,"DIHCOR") -void DihedralCorrelation::registerKeywords( Keywords& keys ){ +void DihedralCorrelation::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); keys.add("numbered","ATOMS","the atoms involved in each of the dihedral correlation values you wish to calculate. " - "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one dihedral correlation will be " - "calculated for each ATOM keyword you specify (all ATOM keywords should " - "specify the indices of 8 atoms). The eventual number of quantities calculated by this " - "action will depend on what functions of the distribution you choose to calculate."); + "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one dihedral correlation will be " + "calculated for each ATOM keyword you specify (all ATOM keywords should " + "specify the indices of 8 atoms). The eventual number of quantities calculated by this " + "action will depend on what functions of the distribution you choose to calculate."); keys.reset_style("ATOMS","atoms"); } DihedralCorrelation::DihedralCorrelation(const ActionOptions&ao): -Action(ao), -MultiColvarBase(ao) + Action(ao), + MultiColvarBase(ao) { // Read in the atoms std::vector<AtomNumber> all_atoms; readAtomsLikeKeyword( "ATOMS", 8, all_atoms ); setupMultiColvarBase( all_atoms ); // Stuff for central atoms - std::vector<bool> catom_ind(8, false); + std::vector<bool> catom_ind(8, false); catom_ind[1]=catom_ind[2]=catom_ind[5]=catom_ind[6]=true; setAtomsForCentralAtom( catom_ind ); // And setup the ActionWithVessel - if( getNumberOfVessels()==0 ){ - std::string fake_input; - addVessel( "SUM", fake_input, -1 ); // -1 here means that this value will be named getLabel() - readVesselKeywords(); // This makes sure resizing is done + if( getNumberOfVessels()==0 ) { + std::string fake_input; + addVessel( "SUM", fake_input, -1 ); // -1 here means that this value will be named getLabel() + readVesselKeywords(); // This makes sure resizing is done } // And check everything has been read in correctly @@ -148,9 +148,9 @@ double DihedralCorrelation::compute( const unsigned& tindex, AtomValuePack& myat const double value = 0.5*(1.+cos(diff)); // Derivatives wrt phi1 const double dval = 0.5*sin(diff); - dd10 *= dval; - dd11 *= dval; - dd12 *= dval; + dd10 *= dval; + dd11 *= dval; + dd12 *= dval; // And add addAtomDerivatives(1, 0, dd10, myatoms ); addAtomDerivatives(1, 1, dd11-dd10, myatoms ); diff --git a/src/multicolvar/DistanceFromContour.cpp b/src/multicolvar/DistanceFromContour.cpp index 3a942c5fb..214930392 100644 --- a/src/multicolvar/DistanceFromContour.cpp +++ b/src/multicolvar/DistanceFromContour.cpp @@ -31,7 +31,7 @@ Calculate the perpendicular distance from a Willard-Chandler dividing surface. Suppose that you have calculated a multicolvar. By doing so you have calculated a -set of colvars, \f$s_i\f$, and each of these colvars has a well defined position in +set of colvars, \f$s_i\f$, and each of these colvars has a well defined position in space \f$(x_i,y_i,z_i)\f$. You can use this information to calculate a phase-field model of the colvar density using: @@ -39,7 +39,7 @@ model of the colvar density using: p(x,y,x) = \sum_{i} s_i K\left[\frac{x-x_i}{\sigma_x},\frac{y-y_i}{\sigma_y},\frac{z-z_i}{\sigma_z} \right] \f] -In this expression \f$\sigma_x, \sigma_y\f$ and \f$\sigma_z\f$ are bandwidth parameters and +In this expression \f$\sigma_x, \sigma_y\f$ and \f$\sigma_z\f$ are bandwidth parameters and \f$K\f$ is one of the \ref kernelfunctions. This is what is done within \ref MULTICOLVARDENS The Willard-Chandler surface is a surface of constant density in the above phase field \f$p(x,y,z)\f$. @@ -50,13 +50,13 @@ p(x',y',z') = \rho \f] where \f$\rho\f$ is some target density. This action caculates the distance projected on the \f$x, y\f$ or -\f$z\f$ axis between the position of some test particle and this surface of constant field density. +\f$z\f$ axis between the position of some test particle and this surface of constant field density. \par Examples -In this example atoms 2-100 are assumed to be concentraed along some part of the \f$z\f$ axis so that you -an interface between a liquid/solid and the vapour. The quantity dc measures the distance between the -surface at which the density of 2-100 atoms is equal to 0.2 and the position of the test particle atom 1. +In this example atoms 2-100 are assumed to be concentraed along some part of the \f$z\f$ axis so that you +an interface between a liquid/solid and the vapour. The quantity dc measures the distance between the +surface at which the density of 2-100 atoms is equal to 0.2 and the position of the test particle atom 1. \verbatim dens: DENSITY SPECIES=2-100 @@ -81,7 +81,7 @@ private: std::vector<double> bw, pos1, pos2, dirv, dirv2; std::vector<double> forces; std::vector<unsigned> perp_dirs; - vesselbase::ValueVessel* myvalue_vessel; + vesselbase::ValueVessel* myvalue_vessel; vesselbase::ValueVessel* myderiv_vessel; RootFindingBase<DistanceFromContour> mymin; public: @@ -91,16 +91,16 @@ public: bool isDensity() const { return true; } void calculate(); unsigned getNumberOfQuantities() const ; - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } double compute( const unsigned& tindex, AtomValuePack& myatoms ) const ; double getDifferenceFromContour( const std::vector<double>& x, std::vector<double>& der ); -// We need an apply action as we are using an independent value +// We need an apply action as we are using an independent value void apply(); }; PLUMED_REGISTER_ACTION(DistanceFromContour,"DISTANCE_FROM_CONTOUR") -void DistanceFromContour::registerKeywords( Keywords& keys ){ +void DistanceFromContour::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); keys.addOutputComponent("dist1","default","the distance between the reference atom and the nearest contour"); keys.addOutputComponent("dist2","default","the distance between the reference atom and the other contour"); @@ -110,31 +110,31 @@ void DistanceFromContour::registerKeywords( Keywords& keys ){ keys.add("atoms","ATOM","The atom whose perpendicular distance we are calculating from the contour"); keys.add("compulsory","BANDWIDTH","the bandwidths for kernel density esimtation"); keys.add("compulsory","KERNEL","gaussian","the kernel function you are using. More details on the kernels available " - "in plumed plumed can be found in \\ref kernelfunctions."); + "in plumed plumed can be found in \\ref kernelfunctions."); keys.add("compulsory","DIR","the direction perpendicular to the contour that you are looking for"); keys.add("compulsory","CONTOUR","the value we would like for the contour"); keys.add("compulsory","TOLERANCE","0.1","this parameter is used to manage periodic boundary conditions. The problem " - "here is that we can be between contours even when we are not within the membrane " - "because of periodic boundary conditions. When we are in the contour, however, we " - "should have it so that the sums of the absoluate values of the distances to the two " - "contours is approximately the distance between the two contours. There can be numerical errors in these calculations, however, so " - "we specify a small tolerance here"); + "here is that we can be between contours even when we are not within the membrane " + "because of periodic boundary conditions. When we are in the contour, however, we " + "should have it so that the sums of the absoluate values of the distances to the two " + "contours is approximately the distance between the two contours. There can be numerical errors in these calculations, however, so " + "we specify a small tolerance here"); } DistanceFromContour::DistanceFromContour( const ActionOptions& ao ): -Action(ao), -MultiColvarBase(ao), -derivTime(false), -bw(3), -pos1(3,0.0), -pos2(3,0.0), -dirv(3,0.0), -dirv2(3,0.0), -perp_dirs(2), -mymin(this) + Action(ao), + MultiColvarBase(ao), + derivTime(false), + bw(3), + pos1(3,0.0), + pos2(3,0.0), + dirv(3,0.0), + dirv2(3,0.0), + perp_dirs(2), + mymin(this) { // Read in the multicolvar/atoms - std::vector<AtomNumber> all_atoms; parse("TOLERANCE",pbc_param); + std::vector<AtomNumber> all_atoms; parse("TOLERANCE",pbc_param); bool read2 = parseMultiColvarAtomList("DATA", -1, all_atoms); if( !read2 ) error("missing DATA keyword"); bool read1 = parseMultiColvarAtomList("ATOM", -1, all_atoms); @@ -146,10 +146,10 @@ mymin(this) if( getNumberOfBaseMultiColvars()!=1 ) error("should only be one input multicolvar"); // Get the direction - std::string ldir; parse("DIR",ldir ); - if( ldir=="x" ){ dir=0; perp_dirs[0]=1; perp_dirs[1]=2; dirv[0]=1; dirv2[0]=-1; } - else if( ldir=="y" ){ dir=1; perp_dirs[0]=0; perp_dirs[1]=2; dirv[1]=1; dirv2[1]=-1; } - else if( ldir=="z" ){ dir=2; perp_dirs[0]=0; perp_dirs[1]=1; dirv[2]=1; dirv2[2]=-1; } + std::string ldir; parse("DIR",ldir ); + if( ldir=="x" ) { dir=0; perp_dirs[0]=1; perp_dirs[1]=2; dirv[0]=1; dirv2[0]=-1; } + else if( ldir=="y" ) { dir=1; perp_dirs[0]=0; perp_dirs[1]=2; dirv[1]=1; dirv2[1]=-1; } + else if( ldir=="z" ) { dir=2; perp_dirs[0]=0; perp_dirs[1]=1; dirv[2]=1; dirv2[2]=-1; } else error(ldir + " is not a valid direction use x, y or z"); // Read in details of phase field construction @@ -158,45 +158,45 @@ mymin(this) log.printf(" constructing phase field using %s kernels with bandwidth (%f, %f, %f) \n",kerneltype.c_str(), bw[0], bw[1], bw[2] ); // Now create a task list - for(unsigned i=0;i<mybasemulticolvars[0]->getFullNumberOfTasks();++i) addTaskToList(i); + for(unsigned i=0; i<mybasemulticolvars[0]->getFullNumberOfTasks(); ++i) addTaskToList(i); // And a cutoff std::vector<double> pp( bw.size(),0 ); KernelFunctions kernel( pp, bw, kerneltype, false, 1.0, true ); - double rcut = kernel.getCutoff( bw[0] ); - for(unsigned j=1;j<bw.size();++j){ - if( kernel.getCutoff(bw[j])>rcut ) rcut=kernel.getCutoff(bw[j]); + double rcut = kernel.getCutoff( bw[0] ); + for(unsigned j=1; j<bw.size(); ++j) { + if( kernel.getCutoff(bw[j])>rcut ) rcut=kernel.getCutoff(bw[j]); } - rcut2=rcut*rcut; - // Create the values + rcut2=rcut*rcut; + // Create the values addComponent("thickness"); componentIsNotPeriodic("thickness"); addComponent("dist1"); componentIsNotPeriodic("dist1"); addComponent("dist2"); componentIsNotPeriodic("dist2"); addComponentWithDerivatives("qdist"); componentIsNotPeriodic("qdist"); - // Create sum vessels + // Create sum vessels std::string fake_input; std::string deriv_input="COMPONENT=2"; - if( mybasemulticolvars[0]->isDensity() ){ - addVessel( "SUM", fake_input, -1 ); addVessel( "SUM", deriv_input, -1 ); - } else { - addVessel( "MEAN", fake_input, -1 ); addVessel( "MEAN", deriv_input, -1 ); + if( mybasemulticolvars[0]->isDensity() ) { + addVessel( "SUM", fake_input, -1 ); addVessel( "SUM", deriv_input, -1 ); + } else { + addVessel( "MEAN", fake_input, -1 ); addVessel( "MEAN", deriv_input, -1 ); } // And convert to a value vessel so we can get the final value myvalue_vessel = dynamic_cast<vesselbase::ValueVessel*>( getPntrToVessel(0) ); - myderiv_vessel = dynamic_cast<vesselbase::ValueVessel*>( getPntrToVessel(1) ); - plumed_assert( myvalue_vessel && myderiv_vessel ); resizeFunctions(); + myderiv_vessel = dynamic_cast<vesselbase::ValueVessel*>( getPntrToVessel(1) ); + plumed_assert( myvalue_vessel && myderiv_vessel ); resizeFunctions(); // Create the vector of values that holds the position - for(unsigned i=0;i<3;++i) pval.push_back( new Value() ); + for(unsigned i=0; i<3; ++i) pval.push_back( new Value() ); } -DistanceFromContour::~DistanceFromContour(){ - for(unsigned i=0;i<3;++i) delete pval[i]; +DistanceFromContour::~DistanceFromContour() { + for(unsigned i=0; i<3; ++i) delete pval[i]; } unsigned DistanceFromContour::getNumberOfQuantities() const { return 3; } -void DistanceFromContour::calculate(){ +void DistanceFromContour::calculate() { // Check box is orthorhombic if( !getPbc().isOrthorombic() ) error("cell box must be orthorhombic"); @@ -207,14 +207,14 @@ void DistanceFromContour::calculate(){ deactivateAllTasks(); Vector myvec = getSeparation( getPosition(getNumberOfAtoms()-1), getPosition(0) ); pos2[dir]=myvec[dir]; taskFlags[0]=1; double d2, mindist = myvec.modulo2(); - for(unsigned j=1;j<getNumberOfAtoms()-1;++j){ - Vector distance=getSeparation( getPosition(getNumberOfAtoms()-1), getPosition(j) ); - if( (d2=distance[perp_dirs[0]]*distance[perp_dirs[0]])<rcut2 && - (d2+=distance[perp_dirs[1]]*distance[perp_dirs[1]])<rcut2 ){ - d2+=distance[dir]*distance[dir]; - if( d2<mindist && fabs(distance[dir])>epsilon ){ pos2[dir]=distance[dir]; mindist = d2; } - taskFlags[j]=1; - } + for(unsigned j=1; j<getNumberOfAtoms()-1; ++j) { + Vector distance=getSeparation( getPosition(getNumberOfAtoms()-1), getPosition(j) ); + if( (d2=distance[perp_dirs[0]]*distance[perp_dirs[0]])<rcut2 && + (d2+=distance[perp_dirs[1]]*distance[perp_dirs[1]])<rcut2 ) { + d2+=distance[dir]*distance[dir]; + if( d2<mindist && fabs(distance[dir])>epsilon ) { pos2[dir]=distance[dir]; mindist = d2; } + taskFlags[j]=1; + } } lockContributors(); derivTime=false; // pos1 position of the nanoparticle, in the first time @@ -224,29 +224,29 @@ void DistanceFromContour::calculate(){ std::vector<double> faked(3); double fa = getDifferenceFromContour( pos1, faked ); double fb = getDifferenceFromContour( pos2, faked ); - if( fa*fb>0 ){ - unsigned maxtries = std::floor( ( getBox()(dir,dir) ) / bw[dir] ); - for(unsigned i=0;i<maxtries;++i){ - double sign=(pos2[dir]>0)? -1 : +1; // If the nanoparticle is inside the membrane push it out - pos1[dir] += sign*bw[dir]; fa = getDifferenceFromContour( pos1, faked ); - if( fa*fb<0 ) break; - // if fa*fb is less than zero the new pos 1 is outside the contour - } + if( fa*fb>0 ) { + unsigned maxtries = std::floor( ( getBox()(dir,dir) ) / bw[dir] ); + for(unsigned i=0; i<maxtries; ++i) { + double sign=(pos2[dir]>0)? -1 : +1; // If the nanoparticle is inside the membrane push it out + pos1[dir] += sign*bw[dir]; fa = getDifferenceFromContour( pos1, faked ); + if( fa*fb<0 ) break; + // if fa*fb is less than zero the new pos 1 is outside the contour + } } // Set direction for contour search - dirv[dir] = pos2[dir] - pos1[dir]; + dirv[dir] = pos2[dir] - pos1[dir]; // Bracket for second root starts in center of membrane - double fc = getDifferenceFromContour( pos2, faked ); - if( fc*fb>0 ){ - // first time is true, because fc=fb - // push pos2 from its initial position inside the membrane towards the second contourn - unsigned maxtries = std::floor( ( getBox()(dir,dir) ) / bw[dir] ); - for(unsigned i=0;i<maxtries;++i){ - double sign=(dirv[dir]>0)? +1 : -1; - pos2[dir] += sign*bw[dir]; fc = getDifferenceFromContour( pos2, faked ); - if( fc*fb<0 ) break; - } - dirv2[dir] = ( pos1[dir] + dirv[dir] ) - pos2[dir]; + double fc = getDifferenceFromContour( pos2, faked ); + if( fc*fb>0 ) { + // first time is true, because fc=fb + // push pos2 from its initial position inside the membrane towards the second contourn + unsigned maxtries = std::floor( ( getBox()(dir,dir) ) / bw[dir] ); + for(unsigned i=0; i<maxtries; ++i) { + double sign=(dirv[dir]>0)? +1 : -1; + pos2[dir] += sign*bw[dir]; fc = getDifferenceFromContour( pos2, faked ); + if( fc*fb<0 ) break; + } + dirv2[dir] = ( pos1[dir] + dirv[dir] ) - pos2[dir]; } // Now do a search for the two contours @@ -255,50 +255,50 @@ void DistanceFromContour::calculate(){ Vector root1; root1.zero(); root1[dir] = pval[dir]->get(); mymin.lsearch( dirv2, pos2, &DistanceFromContour::getDifferenceFromContour ); // Calculate the separation between the two roots using PBC - Vector root2; root2.zero(); root2[dir]=pval[dir]->get(); + Vector root2; root2.zero(); root2[dir]=pval[dir]->get(); Vector sep = getSeparation( root1, root2 ); double spacing = fabs( sep[dir] ); plumed_assert( spacing>epsilon ); getPntrToComponent("thickness")->set( spacing ); // Make sure the sign is right - double predir=(root1[dir]*root2[dir]<0)? -1 : 1; - // This deals with periodic boundary conditions - if we are inside the membrane the sum of the absolute + double predir=(root1[dir]*root2[dir]<0)? -1 : 1; + // This deals with periodic boundary conditions - if we are inside the membrane the sum of the absolute // distances from the contours should add up to the spacing. When this is not the case we must be outside // the contour - // if( predir==-1 && (fabs(root1[dir])+fabs(root2[dir]))>(spacing+pbc_param) ) predir=1; + // if( predir==-1 && (fabs(root1[dir])+fabs(root2[dir]))>(spacing+pbc_param) ) predir=1; // Set the final value to root that is closest to the "origin" = position of atom - if( fabs(root1[dir])<fabs(root2[dir]) ){ - getPntrToComponent("dist1")->set( predir*fabs(root1[dir]) ); - getPntrToComponent("dist2")->set( fabs(root2[dir]) ); - } else { - getPntrToComponent("dist1")->set( predir*fabs(root2[dir]) ); - getPntrToComponent("dist2")->set( fabs(root1[dir]) ); + if( fabs(root1[dir])<fabs(root2[dir]) ) { + getPntrToComponent("dist1")->set( predir*fabs(root1[dir]) ); + getPntrToComponent("dist2")->set( fabs(root2[dir]) ); + } else { + getPntrToComponent("dist1")->set( predir*fabs(root2[dir]) ); + getPntrToComponent("dist2")->set( fabs(root1[dir]) ); } getPntrToComponent("qdist")->set( root2[dir]*root1[dir] ); // Now calculate the derivatives - if( !doNotCalculateDerivatives() ){ - Value* ival=myvalue_vessel->getFinalValue(); ival->clearDerivatives(); - std::vector<double> root1v(3); for(unsigned i=0;i<3;++i) root1v[i]=root1[i]; - derivTime=true; std::vector<double> der(3); getDifferenceFromContour( root1v, der ); double prefactor; - if( mybasemulticolvars[0]->isDensity() ) prefactor = root2[dir] / myderiv_vessel->getOutputValue(); - else plumed_error(); - Value* val=getPntrToComponent("qdist"); - for(unsigned i=0;i<val->getNumberOfDerivatives();++i) val->setDerivative( i, -prefactor*ival->getDerivative(i) ); - ival->clearDerivatives(); - std::vector<double> root2v(3); for(unsigned i=0;i<3;++i) root2v[i]=root2[i]; - getDifferenceFromContour( root2v, der ); - if( mybasemulticolvars[0]->isDensity() ) prefactor = root1[dir] / myderiv_vessel->getOutputValue(); - else plumed_error(); - for(unsigned i=0;i<val->getNumberOfDerivatives();++i) val->addDerivative( i, -prefactor*ival->getDerivative(i) ); + if( !doNotCalculateDerivatives() ) { + Value* ival=myvalue_vessel->getFinalValue(); ival->clearDerivatives(); + std::vector<double> root1v(3); for(unsigned i=0; i<3; ++i) root1v[i]=root1[i]; + derivTime=true; std::vector<double> der(3); getDifferenceFromContour( root1v, der ); double prefactor; + if( mybasemulticolvars[0]->isDensity() ) prefactor = root2[dir] / myderiv_vessel->getOutputValue(); + else plumed_error(); + Value* val=getPntrToComponent("qdist"); + for(unsigned i=0; i<val->getNumberOfDerivatives(); ++i) val->setDerivative( i, -prefactor*ival->getDerivative(i) ); + ival->clearDerivatives(); + std::vector<double> root2v(3); for(unsigned i=0; i<3; ++i) root2v[i]=root2[i]; + getDifferenceFromContour( root2v, der ); + if( mybasemulticolvars[0]->isDensity() ) prefactor = root1[dir] / myderiv_vessel->getOutputValue(); + else plumed_error(); + for(unsigned i=0; i<val->getNumberOfDerivatives(); ++i) val->addDerivative( i, -prefactor*ival->getDerivative(i) ); } } -double DistanceFromContour::getDifferenceFromContour( const std::vector<double>& x, std::vector<double>& der ){ - std::string min, max; - for(unsigned j=0;j<3;++j){ - Tools::convert( -0.5*getBox()(j,j), min ); - Tools::convert( +0.5*getBox()(j,j), max ); - pval[j]->setDomain( min, max ); pval[j]->set( x[j] ); +double DistanceFromContour::getDifferenceFromContour( const std::vector<double>& x, std::vector<double>& der ) { + std::string min, max; + for(unsigned j=0; j<3; ++j) { + Tools::convert( -0.5*getBox()(j,j), min ); + Tools::convert( +0.5*getBox()(j,j), max ); + pval[j]->setDomain( min, max ); pval[j]->set( x[j] ); } runAllTasks(); return myvalue_vessel->getOutputValue() - contour; @@ -306,24 +306,24 @@ double DistanceFromContour::getDifferenceFromContour( const std::vector<double>& double DistanceFromContour::compute( const unsigned& tindex, AtomValuePack& myatoms ) const { Vector distance = getSeparation( getPosition(getNumberOfAtoms()-1), myatoms.getPosition(0) ); - std::vector<double> pp(3), der(3,0); for(unsigned j=0;j<3;++j) pp[j] = distance[j]; + std::vector<double> pp(3), der(3,0); for(unsigned j=0; j<3; ++j) pp[j] = distance[j]; // Now create the kernel and evaluate KernelFunctions kernel( pp, bw, kerneltype, false, 1.0, true ); double newval = kernel.evaluate( pval, der, true ); - if( mybasemulticolvars[0]->isDensity() ){ - if( !doNotCalculateDerivatives() && derivTime ){ - MultiValue& myvals=myatoms.getUnderlyingMultiValue(); - Vector vder; unsigned basen=myvals.getNumberOfDerivatives() - 12; - for(unsigned i=0;i<3;++i){ - vder[i]=der[i]; myvals.addDerivative( 1, basen+i, vder[i] ); - } - myatoms.setValue( 2, der[dir] ); - addAtomDerivatives( 1, 0, -vder, myatoms ); - myatoms.addBoxDerivatives( 1, Tensor(vder,distance) ); + if( mybasemulticolvars[0]->isDensity() ) { + if( !doNotCalculateDerivatives() && derivTime ) { + MultiValue& myvals=myatoms.getUnderlyingMultiValue(); + Vector vder; unsigned basen=myvals.getNumberOfDerivatives() - 12; + for(unsigned i=0; i<3; ++i) { + vder[i]=der[i]; myvals.addDerivative( 1, basen+i, vder[i] ); } - myatoms.setValue( 0, 1.0 ); return newval; + myatoms.setValue( 2, der[dir] ); + addAtomDerivatives( 1, 0, -vder, myatoms ); + myatoms.addBoxDerivatives( 1, Tensor(vder,distance) ); + } + myatoms.setValue( 0, 1.0 ); return newval; } // This does the stuff for averaging @@ -332,10 +332,10 @@ double DistanceFromContour::compute( const unsigned& tindex, AtomValuePack& myat // This gets the average if we are using a phase field std::vector<double> cvals( mybasemulticolvars[0]->getNumberOfQuantities() ); mybasedata[0]->retrieveValueWithIndex( tindex, false, cvals ); - return newval*cvals[0]*cvals[1]; + return newval*cvals[0]*cvals[1]; } -void DistanceFromContour::apply(){ +void DistanceFromContour::apply() { if( getPntrToComponent("qdist")->applyForce( forces ) ) setForcesOnAtoms( forces ); } diff --git a/src/multicolvar/Distances.cpp b/src/multicolvar/Distances.cpp index 4ea6d867e..d5cb8fde0 100644 --- a/src/multicolvar/Distances.cpp +++ b/src/multicolvar/Distances.cpp @@ -30,17 +30,17 @@ using namespace std; -namespace PLMD{ -namespace multicolvar{ +namespace PLMD { +namespace multicolvar { //+PLUMEDOC MCOLVAR DISTANCES /* Calculate the distances between one or many pairs of atoms. You can then calculate functions of the distribution of -distances such as the minimum, the number less than a certain quantity and so on. +distances such as the minimum, the number less than a certain quantity and so on. \par Examples -The following input tells plumed to calculate the distances between atoms 3 and 5 and between atoms 1 and 2 and to +The following input tells plumed to calculate the distances between atoms 3 and 5 and between atoms 1 and 2 and to print the minimum for these two distances. \verbatim DISTANCES ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1} LABEL=d1 @@ -70,7 +70,7 @@ In other words the distances between atoms 1 and 2 and the distance between atom more than 0.1 is then printed to a file. \verbatim DISTANCES GROUPA=1 GROUPB=2,3 MORE_THAN={RATIONAL R_0=0.1} -PRINT ARG=d1.gt0.1 +PRINT ARG=d1.gt0.1 \endverbatim (See also \ref PRINT \ref switchingfunction) @@ -80,7 +80,7 @@ PRINT ARG=d1.gt0.1 To calculate and print the minimum distance between two groups of atoms you use the following commands \verbatim -d1: DISTANCES GROUPA=1-10 GROUPB=11-20 MIN={BETA=500.} +d1: DISTANCES GROUPA=1-10 GROUPB=11-20 MIN={BETA=500.} PRINT ARG=d1.min FILE=colvar STRIDE=10 \endverbatim (see \ref DISTANCES and \ref PRINT) @@ -93,29 +93,29 @@ s = \frac{\beta}{ \log \sum_i \exp\left( \frac{\beta}{s_i} \right) } where \f$\beta\f$ is a user specified parameter. -This input is used rather than a separate MINDIST colvar so that the same routine and the same input style can be -used to calculate minimum coordinatetion numbers (see \ref COORDINATIONNUMBER), minimum -angles (see \ref ANGLES) and many other variables. +This input is used rather than a separate MINDIST colvar so that the same routine and the same input style can be +used to calculate minimum coordinatetion numbers (see \ref COORDINATIONNUMBER), minimum +angles (see \ref ANGLES) and many other variables. This new way of calculating mindist is part of plumed 2's multicolvar functionality. These special actions -allow you to calculate multiple functions of a distribution of simple collective variables. As an example you +allow you to calculate multiple functions of a distribution of simple collective variables. As an example you can calculate the number of distances less than 1.0, the minimum distance, the number of distances more than 2.0 and the number of distances between 1.0 and 2.0 by using the following command: \verbatim DISTANCES ... - GROUPA=1-10 GROUPB=11-20 - LESS_THAN={RATIONAL R_0=1.0} - MORE_THAN={RATIONAL R_0=2.0} - BETWEEN={GAUSSIAN LOWER=1.0 UPPER=2.0} + GROUPA=1-10 GROUPB=11-20 + LESS_THAN={RATIONAL R_0=1.0} + MORE_THAN={RATIONAL R_0=2.0} + BETWEEN={GAUSSIAN LOWER=1.0 UPPER=2.0} MIN={BETA=500.} ... DISTANCES PRINT ARG=d1.lessthan,d1.morethan,d1.between,d1.min FILE=colvar STRIDE=10 \endverbatim (see \ref DISTANCES and \ref PRINT) -A calculation performed this way is fast because the expensive part of the calculation - the calculation of all the distances - is only -done once per step. Furthermore, it can be made faster by using the TOL keyword to discard those distance that make only a small contributions +A calculation performed this way is fast because the expensive part of the calculation - the calculation of all the distances - is only +done once per step. Furthermore, it can be made faster by using the TOL keyword to discard those distance that make only a small contributions to the final values together with the NL_STRIDE keyword, which ensures that the distances that make only a small contribution to the final values aren't calculated at every step. @@ -131,35 +131,35 @@ public: // active methods: virtual double compute( const unsigned& tindex, AtomValuePack& myatoms ) const ; /// Returns the number of coordinates of the field - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } }; PLUMED_REGISTER_ACTION(Distances,"DISTANCES") -void Distances::registerKeywords( Keywords& keys ){ +void Distances::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); - keys.use("ALT_MIN"); keys.use("LOWEST"); keys.use("HIGHEST"); + keys.use("ALT_MIN"); keys.use("LOWEST"); keys.use("HIGHEST"); keys.use("MEAN"); keys.use("MIN"); keys.use("MAX"); keys.use("LESS_THAN"); // keys.use("DHENERGY"); keys.use("MORE_THAN"); keys.use("BETWEEN"); keys.use("HISTOGRAM"); keys.use("MOMENTS"); keys.add("numbered","ATOMS","the atoms involved in each of the distances you wish to calculate. " - "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one distance will be " - "calculated for each ATOM keyword you specify (all ATOM keywords should " - "specify the indices of two atoms). The eventual number of quantities calculated by this " - "action will depend on what functions of the distribution you choose to calculate."); + "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one distance will be " + "calculated for each ATOM keyword you specify (all ATOM keywords should " + "specify the indices of two atoms). The eventual number of quantities calculated by this " + "action will depend on what functions of the distribution you choose to calculate."); keys.reset_style("ATOMS","atoms"); keys.add("atoms-1","GROUP","Calculate the distance between each distinct pair of atoms in the group"); keys.add("atoms-2","GROUPA","Calculate the distances between all the atoms in GROUPA and all " - "the atoms in GROUPB. This must be used in conjuction with GROUPB."); + "the atoms in GROUPB. This must be used in conjuction with GROUPB."); keys.add("atoms-2","GROUPB","Calculate the distances between all the atoms in GROUPA and all the atoms " - "in GROUPB. This must be used in conjuction with GROUPA."); + "in GROUPB. This must be used in conjuction with GROUPA."); } Distances::Distances(const ActionOptions&ao): -Action(ao), -MultiColvarBase(ao) + Action(ao), + MultiColvarBase(ao) { // Read in the atoms - std::vector<AtomNumber> all_atoms; + std::vector<AtomNumber> all_atoms; readTwoGroups( "GROUP", "GROUPA", "GROUPB", all_atoms ); if( atom_lab.size()==0 ) readAtomsLikeKeyword( "ATOMS", 2, all_atoms ); setupMultiColvarBase( all_atoms ); @@ -168,44 +168,44 @@ MultiColvarBase(ao) // Now check if we can use link cells bool use_link=false; double rcut; - if( getNumberOfVessels()>0 ){ - vesselbase::LessThan* lt=dynamic_cast<vesselbase::LessThan*>( getPntrToVessel(0) ); - if( lt ){ - use_link=true; rcut=lt->getCutoff(); - } else { - vesselbase::Between* bt=dynamic_cast<vesselbase::Between*>( getPntrToVessel(0) ); - if( bt ){ use_link=true; rcut=bt->getCutoff(); } - } - if( use_link ){ - for(unsigned i=1;i<getNumberOfVessels();++i){ - vesselbase::LessThan* lt2=dynamic_cast<vesselbase::LessThan*>( getPntrToVessel(i) ); - vesselbase::Between* bt=dynamic_cast<vesselbase::Between*>( getPntrToVessel(i) ); - if( lt2 ){ - double tcut=lt2->getCutoff(); - if( tcut>rcut ) rcut=tcut; - } else if( bt ){ - double tcut=bt->getCutoff(); - if( tcut>rcut ) rcut=tcut; - } else { - use_link=false; - } - } - } - if( use_link ) setLinkCellCutoff( rcut ); + if( getNumberOfVessels()>0 ) { + vesselbase::LessThan* lt=dynamic_cast<vesselbase::LessThan*>( getPntrToVessel(0) ); + if( lt ) { + use_link=true; rcut=lt->getCutoff(); + } else { + vesselbase::Between* bt=dynamic_cast<vesselbase::Between*>( getPntrToVessel(0) ); + if( bt ) { use_link=true; rcut=bt->getCutoff(); } + } + if( use_link ) { + for(unsigned i=1; i<getNumberOfVessels(); ++i) { + vesselbase::LessThan* lt2=dynamic_cast<vesselbase::LessThan*>( getPntrToVessel(i) ); + vesselbase::Between* bt=dynamic_cast<vesselbase::Between*>( getPntrToVessel(i) ); + if( lt2 ) { + double tcut=lt2->getCutoff(); + if( tcut>rcut ) rcut=tcut; + } else if( bt ) { + double tcut=bt->getCutoff(); + if( tcut>rcut ) rcut=tcut; + } else { + use_link=false; + } + } + } + if( use_link ) setLinkCellCutoff( rcut ); } } double Distances::compute( const unsigned& tindex, AtomValuePack& myatoms ) const { - Vector distance; - distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); - const double value=distance.modulo(); - const double invvalue=1.0/value; - - // And finish the calculation - addAtomDerivatives( 1, 0,-invvalue*distance, myatoms ); - addAtomDerivatives( 1, 1, invvalue*distance, myatoms ); - myatoms.addBoxDerivatives( 1, -invvalue*Tensor(distance,distance) ); - return value; + Vector distance; + distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); + const double value=distance.modulo(); + const double invvalue=1.0/value; + + // And finish the calculation + addAtomDerivatives( 1, 0,-invvalue*distance, myatoms ); + addAtomDerivatives( 1, 1, invvalue*distance, myatoms ); + myatoms.addBoxDerivatives( 1, -invvalue*Tensor(distance,distance) ); + return value; } } diff --git a/src/multicolvar/DumpMultiColvar.cpp b/src/multicolvar/DumpMultiColvar.cpp index 39760fbd4..27029a436 100644 --- a/src/multicolvar/DumpMultiColvar.cpp +++ b/src/multicolvar/DumpMultiColvar.cpp @@ -40,13 +40,13 @@ namespace PLMD { namespace multicolvar { -//+PLUMEDOC PRINTANALYSIS DUMPMULTICOLVAR +//+PLUMEDOC PRINTANALYSIS DUMPMULTICOLVAR /* Dump atom positions and multicolvar on a file. \par Examples -In this examples we calculate the distances between the atoms of the first and the second -group and we write them in the file MULTICOLVAR.xyz. For each couple it writes the +In this examples we calculate the distances between the atoms of the first and the second +group and we write them in the file MULTICOLVAR.xyz. For each couple it writes the coordinates of their geometric center and their distance. \verbatim @@ -69,21 +69,21 @@ class DumpMultiColvar: { OFile of; double lenunit; - MultiColvarBase* mycolv; + MultiColvarBase* mycolv; std::string fmt_xyz; public: explicit DumpMultiColvar(const ActionOptions&); ~DumpMultiColvar(); static void registerKeywords( Keywords& keys ); - void calculate(){} - void calculateNumericalDerivatives( ActionWithValue* vv ){ plumed_error(); } - void apply(){} + void calculate() {} + void calculateNumericalDerivatives( ActionWithValue* vv ) { plumed_error(); } + void apply() {} void update(); }; PLUMED_REGISTER_ACTION(DumpMultiColvar,"DUMPMULTICOLVAR") -void DumpMultiColvar::registerKeywords( Keywords& keys ){ +void DumpMultiColvar::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionAtomistic::registerKeywords( keys ); ActionPilot::registerKeywords( keys ); @@ -103,7 +103,7 @@ DumpMultiColvar::DumpMultiColvar(const ActionOptions&ao): { readArgument("store"); mycolv = dynamic_cast<MultiColvarBase*>( getDependencies()[0] ); - plumed_assert( getDependencies().size()==1 ); + plumed_assert( getDependencies().size()==1 ); if(!mycolv) error("action labeled " + mycolv->getLabel() + " is not a multicolvar"); log.printf(" printing colvars calculated by action %s \n",mycolv->getLabel().c_str() ); @@ -121,7 +121,7 @@ DumpMultiColvar::DumpMultiColvar(const ActionOptions&ao): fmt_xyz="%f"; string precision; parse("PRECISION",precision); - if(precision.length()>0){ + if(precision.length()>0) { int p; Tools::convert(precision,p); log<<" with precision "<<p<<"\n"; string a,b; @@ -131,10 +131,10 @@ DumpMultiColvar::DumpMultiColvar(const ActionOptions&ao): } std::string unitname; parse("UNITS",unitname); - if(unitname!="PLUMED"){ + if(unitname!="PLUMED") { Units myunit; myunit.setLength(unitname); lenunit=plumed.getAtoms().getUnits().getLength()/myunit.getLength(); - } + } else lenunit=1.0; checkRead(); @@ -144,22 +144,22 @@ DumpMultiColvar::DumpMultiColvar(const ActionOptions&ao): requestAtoms(atom); addDependency( mycolv ); } -void DumpMultiColvar::update(){ +void DumpMultiColvar::update() { of.printf("%u\n",mycolv->getCurrentNumberOfActiveTasks()); const Tensor & t(mycolv->getPbc().getBox()); - if(mycolv->getPbc().isOrthorombic()){ + if(mycolv->getPbc().isOrthorombic()) { of.printf((" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+"\n").c_str(),lenunit*t(0,0),lenunit*t(1,1),lenunit*t(2,2)); - }else{ + } else { of.printf((" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz+"\n").c_str(), - lenunit*t(0,0),lenunit*t(0,1),lenunit*t(0,2), - lenunit*t(1,0),lenunit*t(1,1),lenunit*t(1,2), - lenunit*t(2,0),lenunit*t(2,1),lenunit*t(2,2) - ); + lenunit*t(0,0),lenunit*t(0,1),lenunit*t(0,2), + lenunit*t(1,0),lenunit*t(1,1),lenunit*t(1,2), + lenunit*t(2,0),lenunit*t(2,1),lenunit*t(2,2) + ); } vesselbase::StoreDataVessel* stash=dynamic_cast<vesselbase::StoreDataVessel*>( getPntrToArgument() ); plumed_dbg_assert( stash ); std::vector<double> cvals( mycolv->getNumberOfQuantities() ); - for(unsigned i=0;i<mycolv->getCurrentNumberOfActiveTasks();++i){ + for(unsigned i=0; i<mycolv->getCurrentNumberOfActiveTasks(); ++i) { const char* defname="X"; const char* name=defname; @@ -167,18 +167,18 @@ void DumpMultiColvar::update(){ if( getNumberOfAtoms()>0 ) apos=pbcDistance( getPosition(0), apos ); of.printf(("%s "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz).c_str(),name,lenunit*apos[0],lenunit*apos[1],lenunit*apos[2]); stash->retrieveSequentialValue( i, true, cvals ); - if( mycolv->weightWithDerivatives() ){ - for(unsigned j=0;j<cvals.size();++j) of.printf((" "+fmt_xyz).c_str(),cvals[j]); + if( mycolv->weightWithDerivatives() ) { + for(unsigned j=0; j<cvals.size(); ++j) of.printf((" "+fmt_xyz).c_str(),cvals[j]); } else { - for(unsigned j=1;j<cvals.size();++j) of.printf((" "+fmt_xyz).c_str(),cvals[j]); - } + for(unsigned j=1; j<cvals.size(); ++j) of.printf((" "+fmt_xyz).c_str(),cvals[j]); + } of.printf("\n"); } } -DumpMultiColvar::~DumpMultiColvar(){ +DumpMultiColvar::~DumpMultiColvar() { } - + } } diff --git a/src/multicolvar/FilterBetween.cpp b/src/multicolvar/FilterBetween.cpp index 0b94371b6..d6a418711 100644 --- a/src/multicolvar/FilterBetween.cpp +++ b/src/multicolvar/FilterBetween.cpp @@ -27,17 +27,17 @@ /* This action can be useed to transform the colvar values calculated by a multicolvar using a \ref histogrambead -In this action each colvar, \f$s_i\f$, calculated by multicolvar is transformed by a \ref histogrambead function that -is equal to one if the colvar is within a certain range and which is equal to zero otherwise. In other words, we +In this action each colvar, \f$s_i\f$, calculated by multicolvar is transformed by a \ref histogrambead function that +is equal to one if the colvar is within a certain range and which is equal to zero otherwise. In other words, we compute: \f[ f_i = \int_a^b K\left( \frac{s-s_i}{w} \right) \f] -where \f$a, b\f$ and \f$w\f$ are parameters. +where \f$a, b\f$ and \f$w\f$ are parameters. -It is important to understand the distinction between what is done here and what is done by \ref MFILTER_BETWEEN. +It is important to understand the distinction between what is done here and what is done by \ref MFILTER_BETWEEN. In \ref MFILTER_BETWEEN a weight, \f$w_i\f$ for the colvar is calculated using the \ref histogrambead. If one calculates the MEAN for \ref MFILTER_BETWEEN one is thus calculating: @@ -45,53 +45,53 @@ MEAN for \ref MFILTER_BETWEEN one is thus calculating: \mu = \frac{ \sum_i f_i s_i }{ \sum_i f_i} \f] -In this action by contrast the colvar is being transformed by the \ref histogrambead. If one thus calculates a MEAN for +In this action by contrast the colvar is being transformed by the \ref histogrambead. If one thus calculates a MEAN for thia action one computes: \f[ -\mu = \frac{ \sum_{i=1}^N f_i }{ N } +\mu = \frac{ \sum_{i=1}^N f_i }{ N } \f] In other words, you are calculating the mean for the transformed colvar. \par Examples -The following input gives an example of how a MTRANSFORM_BETWEEN action can be used to duplicate -functionality that is elsehwere in PLUMED. +The following input gives an example of how a MTRANSFORM_BETWEEN action can be used to duplicate +functionality that is elsehwere in PLUMED. \verbatim DISTANCES ... GROUPA=1-10 GROUPB=11-20 LABEL=d1 ... DISTANCES -MTRANSFORM_BETWEEN DATA=d1 LOWER=1.0 UPPER=2.0 SMEAR=0.5 +MTRANSFORM_BETWEEN DATA=d1 LOWER=1.0 UPPER=2.0 SMEAR=0.5 \endverbatim In this case you can achieve the same result by using: \verbatim DISTANCES ... - GROUPA=1-10 GROUPB=11-20 - BETWEEN={GAUSSIAN LOWER=1.0 UPPER=2.0} + GROUPA=1-10 GROUPB=11-20 + BETWEEN={GAUSSIAN LOWER=1.0 UPPER=2.0} ... DISTANCES \endverbatim (see \ref DISTANCES) The advantage of MTRANSFORM_BETWEEN comes, however, if you want to use transformed colvars as input -for \ref MULTICOLVARDENS +for \ref MULTICOLVARDENS */ //+ENDPLUMEDOC //+PLUMEDOC MFILTERS MFILTER_BETWEEN /* -This action can be used to filter the colvar values calculated by a multicolvar +This action can be used to filter the colvar values calculated by a multicolvar so that one can compute the mean and so on for only those multicolvars within a certain range. This action can be used to create a dynamic group of atom based on the value of a multicolvar. In this action a multicolvar is within the dynamic group if its value lies in a particular range. In practise a weight, \f$w_i\f$ is ascribed to each colvar, \f$s_i\f$ calculated by a multicolvar -and this weight measures the degree to which a colvar is a member of the group. This weight is +and this weight measures the degree to which a colvar is a member of the group. This weight is calculated using a \ref histogrambead so it is given by: \f[ @@ -99,7 +99,7 @@ w_i = \int_a^b K\left( \frac{s - s_i}{w} \right) \f] where \f$a, b\f$ and \f$w\f$ are parameters. If one calculates a function of the set of multicolvars -these weights are included in the calculation. As such if one calculates the MEAN, \f$\mu\f$ of a filtered +these weights are included in the calculation. As such if one calculates the MEAN, \f$\mu\f$ of a filtered multicolvar what is computed is the following: \f[ @@ -117,10 +117,10 @@ DISTANCES GROUPA=1 GROUPB=2-50 MEAN LABEL=d1 MFILTER_BETWEEN DATA=d1 LOWER=0 UPPER=3.0 SMEAR=0.0001 MEAN LABEL=d4 \endverbatim -More complicated things can be done by using the label of a filter as input to a new multicolvar as shown -in the example below. Here the coordination numbers of all atoms are computed. The atoms with a coordination +More complicated things can be done by using the label of a filter as input to a new multicolvar as shown +in the example below. Here the coordination numbers of all atoms are computed. The atoms with a coordination number between 4 and 6 are then identified using the filter. This reduced list of atoms is then used as input -to a second coordination number calculation. This second coordination number thus measures the number of atoms +to a second coordination number calculation. This second coordination number thus measures the number of atoms 4-6 coordinated atoms each of the 4-6 coordination atoms is bound to. \verbatim @@ -142,52 +142,52 @@ public: static void registerKeywords( Keywords& keys ); explicit FilterBetween(const ActionOptions& ao); double applyFilter( const double& val, double& df ) const ; -}; +}; PLUMED_REGISTER_ACTION(FilterBetween,"MFILTER_BETWEEN") PLUMED_REGISTER_ACTION(FilterBetween,"MTRANSFORM_BETWEEN") -void FilterBetween::registerKeywords( Keywords& keys ){ +void FilterBetween::registerKeywords( Keywords& keys ) { MultiColvarFilter::registerKeywords( keys ); keys.add("compulsory","LOWER","the lower boundary for the range of interest"); keys.add("compulsory","UPPER","the upper boundary for the range of interest"); keys.add("compulsory","SMEAR","0.5","the ammount by which to smear the value for kernel density estimation"); keys.add("optional","BEAD","This keywords is used if you want to employ an alternative to the function defeind above. " - "The following provides information on the \\ref histogrambead that are available. " - "When this keyword is present you no longer need the LOWER, UPPER and SMEAR keywords."); + "The following provides information on the \\ref histogrambead that are available. " + "When this keyword is present you no longer need the LOWER, UPPER and SMEAR keywords."); } FilterBetween::FilterBetween(const ActionOptions& ao): -Action(ao), -MultiColvarFilter(ao) + Action(ao), + MultiColvarFilter(ao) { // Read in the switching function std::string sw, errors; parse("BEAD",sw); - if( getPntrToMultiColvar()->isPeriodic() ){ - std::string min, max; getPntrToMultiColvar()->retrieveDomain( min, max ); - double mlow, mhigh; Tools::convert( min,mlow ); Tools::convert( max, mhigh); - hb.isPeriodic( mlow, mhigh ); + if( getPntrToMultiColvar()->isPeriodic() ) { + std::string min, max; getPntrToMultiColvar()->retrieveDomain( min, max ); + double mlow, mhigh; Tools::convert( min,mlow ); Tools::convert( max, mhigh); + hb.isPeriodic( mlow, mhigh ); } else { - hb.isNotPeriodic(); + hb.isNotPeriodic(); } - if(sw.length()>0){ - hb.set(sw,errors); - if( errors.length()!=0 ) error("problem reading BEAD keyword : " + errors ); + if(sw.length()>0) { + hb.set(sw,errors); + if( errors.length()!=0 ) error("problem reading BEAD keyword : " + errors ); } else { - double l, u, s; std::string ll, uu, ss; - parse("LOWER",l); parse("UPPER",u); parse("SMEAR",s); - Tools::convert(l,ll); Tools::convert(u,uu); Tools::convert(s,ss); - sw="GAUSSIAN LOWER=" + ll + " UPPER=" + uu + " SMEAR=" + ss; - hb.set(sw,errors); plumed_massert(errors.length()==0,"problems with bead" + errors); + double l, u, s; std::string ll, uu, ss; + parse("LOWER",l); parse("UPPER",u); parse("SMEAR",s); + Tools::convert(l,ll); Tools::convert(u,uu); Tools::convert(s,ss); + sw="GAUSSIAN LOWER=" + ll + " UPPER=" + uu + " SMEAR=" + ss; + hb.set(sw,errors); plumed_massert(errors.length()==0,"problems with bead" + errors); } log.printf(" filtering colvar values and focussing only on those values in range %s\n",( hb.description() ).c_str() ); - checkRead(); + checkRead(); } double FilterBetween::applyFilter( const double& val, double& df ) const { - double f = hb.calculate( val, df ); + double f = hb.calculate( val, df ); return f; } diff --git a/src/multicolvar/FilterLessThan.cpp b/src/multicolvar/FilterLessThan.cpp index e24d8ad23..6363bcbb4 100644 --- a/src/multicolvar/FilterLessThan.cpp +++ b/src/multicolvar/FilterLessThan.cpp @@ -27,9 +27,9 @@ /* This action can be useed to transform the colvar values calculated by a multicolvar using a \ref switchingfunction -In this action each colvar, \f$s_i\f$, calculated by multicolvar is transformed by a \ref switchingfunction function that -is equal to one if the colvar is less than a certain target value and which is equal to zero otherwise. -It is important to understand the distinction between what is done here and what is done by \ref MFILTER_LESS. +In this action each colvar, \f$s_i\f$, calculated by multicolvar is transformed by a \ref switchingfunction function that +is equal to one if the colvar is less than a certain target value and which is equal to zero otherwise. +It is important to understand the distinction between what is done here and what is done by \ref MFILTER_LESS. In \ref MFILTER_LESS a weight, \f$w_i\f$ for the colvar is calculated using the \ref switchingfunction. If one calculates the MEAN for \ref MFILTER_LESS one is thus calculating: @@ -37,19 +37,19 @@ MEAN for \ref MFILTER_LESS one is thus calculating: \mu = \frac{ \sum_i \sigma(s_i) s_i }{\sum_i \simga(s_i) } \f] -where \f$\sigma\f$ is the \ref switchingfunction. In this action by contrast the colvar is being transformed by +where \f$\sigma\f$ is the \ref switchingfunction. In this action by contrast the colvar is being transformed by the \ref switchingfunction. If one thus calculates a MEAN for thia action one computes: \f[ -\mu = \frac{ \sum_{i=1}^N \simga(s_i) }{ N } +\mu = \frac{ \sum_{i=1}^N \simga(s_i) }{ N } \f] -In other words, you are calculating the mean for the transformed colvar. +In other words, you are calculating the mean for the transformed colvar. \par Examples -The following input gives an example of how a MTRANSFORM_LESS action can be used to duplicate -functionality that is elsehwere in PLUMED. +The following input gives an example of how a MTRANSFORM_LESS action can be used to duplicate +functionality that is elsehwere in PLUMED. \verbatim DISTANCES ... @@ -63,30 +63,30 @@ In this case you can achieve the same result by using: \verbatim DISTANCES ... - GROUPA=1-10 GROUPB=11-20 + GROUPA=1-10 GROUPB=11-20 LESS_THAN={GAUSSIAN D_0=1.5 R_0=0.00001} ... DISTANCES \endverbatim (see \ref DISTANCES) The advantage of MTRANSFORM_LESS comes, however, if you want to use transformed colvars as input -for \ref MULTICOLVARDENS +for \ref MULTICOLVARDENS */ //+ENDPLUMEDOC //+PLUMEDOC MFILTERS MFILTER_LESS /* -This action can be used to filter the distribution of colvar values in a multicolvar +This action can be used to filter the distribution of colvar values in a multicolvar so that one can compute the mean and so on for only those multicolvars less than a tolerance. This action can be used to create a dynamic group of atom based on the value of a multicolvar. In this action a multicolvar is within the dynamic group if its value is less than a target. In practise a weight, \f$w_i\f$ is ascribed to each colvar, \f$s_i\f$ calculated by a multicolvar -and this weight measures the degree to which a colvar is a member of the group. This weight is a number -between 0 and 1 that is calculated using a \ref switchingfunction , \f$\sigma\f$. +and this weight measures the degree to which a colvar is a member of the group. This weight is a number +between 0 and 1 that is calculated using a \ref switchingfunction , \f$\sigma\f$. If one calculates a function of the set of multicolvars -these weights are included in the calculation. As such if one calculates the MEAN, \f$\mu\f$ of a filtered +these weights are included in the calculation. As such if one calculates the MEAN, \f$\mu\f$ of a filtered multicolvar what is computed is the following: \f[ @@ -117,41 +117,41 @@ public: static void registerKeywords( Keywords& keys ); explicit FilterLess(const ActionOptions& ao); double applyFilter( const double& val, double& df ) const ; -}; +}; PLUMED_REGISTER_ACTION(FilterLess,"MFILTER_LESS") PLUMED_REGISTER_ACTION(FilterLess,"MTRANSFORM_LESS") -void FilterLess::registerKeywords( Keywords& keys ){ +void FilterLess::registerKeywords( Keywords& keys ) { MultiColvarFilter::registerKeywords( keys ); keys.add("compulsory","NN","6","The n parameter of the switching function "); keys.add("compulsory","MM","0","The m parameter of the switching function "); keys.add("compulsory","D_0","0.0","The d_0 parameter of the switching function"); keys.add("compulsory","R_0","The r_0 parameter of the switching function"); keys.add("optional","SWITCH","This keyword is used if you want to employ an alternative to the continuous swiching function defined above. " - "The following provides information on the \\ref switchingfunction that are available. " - "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); + "The following provides information on the \\ref switchingfunction that are available. " + "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); } FilterLess::FilterLess(const ActionOptions& ao): -Action(ao), -MultiColvarFilter(ao) + Action(ao), + MultiColvarFilter(ao) { // Read in the switching function std::string sw, errors; parse("SWITCH",sw); - if(sw.length()>0){ - sf.set(sw,errors); - if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); + if(sw.length()>0) { + sf.set(sw,errors); + if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); } else { - double r_0=-1.0, d_0; int nn, mm; - parse("NN",nn); parse("MM",mm); - parse("R_0",r_0); parse("D_0",d_0); - if( r_0<0.0 ) error("you must set a value for R_0"); - sf.set(nn,mm,r_0,d_0); + double r_0=-1.0, d_0; int nn, mm; + parse("NN",nn); parse("MM",mm); + parse("R_0",r_0); parse("D_0",d_0); + if( r_0<0.0 ) error("you must set a value for R_0"); + sf.set(nn,mm,r_0,d_0); } log.printf(" filtering colvar values and focussing only on those less than %s\n",( sf.description() ).c_str() ); - checkRead(); + checkRead(); } double FilterLess::applyFilter( const double& val, double& df ) const { diff --git a/src/multicolvar/FilterMoreThan.cpp b/src/multicolvar/FilterMoreThan.cpp index 2c0f0e68e..961c33d01 100644 --- a/src/multicolvar/FilterMoreThan.cpp +++ b/src/multicolvar/FilterMoreThan.cpp @@ -27,9 +27,9 @@ /* This action can be useed to transform the colvar values calculated by a multicolvar using one minus a \ref switchingfunction -In this action each colvar, \f$s_i\f$, calculated by multicolvar is transformed by a \ref switchingfunction function that -is equal to one if the colvar is greater than a certain target value and which is equal to zero otherwise. -It is important to understand the distinction between what is done here and what is done by \ref MFILTER_MORE. +In this action each colvar, \f$s_i\f$, calculated by multicolvar is transformed by a \ref switchingfunction function that +is equal to one if the colvar is greater than a certain target value and which is equal to zero otherwise. +It is important to understand the distinction between what is done here and what is done by \ref MFILTER_MORE. In \ref MFILTER_MORE a weight, \f$w_i\f$ for the colvar is calculated using the \ref histogrambead. If one calculates the MEAN for \ref MFILTER_MORE one is thus calculating: @@ -37,19 +37,19 @@ MEAN for \ref MFILTER_MORE one is thus calculating: \mu = \frac{ \sum_i [1 - \sigma(s_i) ] s_i }{\sum_i [1 - \sigma(s_i)] } \f] -where \f$\sigma\f$ is the \ref switchingfunction. In this action by contrast the colvar is being transformed by the \ref switchingfunction. +where \f$\sigma\f$ is the \ref switchingfunction. In this action by contrast the colvar is being transformed by the \ref switchingfunction. If one thus calculates a MEAN for this action one computes: \f[ -\mu = \frac{ \sum_{i=1}^N 1 - \sigma(s_i) }{ N } +\mu = \frac{ \sum_{i=1}^N 1 - \sigma(s_i) }{ N } \f] -In other words, you are calculating the mean for the transformed colvar. +In other words, you are calculating the mean for the transformed colvar. \par Examples -The following input gives an example of how a MTRANSFORM_MORE action can be used to duplicate -functionality that is elsehwere in PLUMED. +The following input gives an example of how a MTRANSFORM_MORE action can be used to duplicate +functionality that is elsehwere in PLUMED. \verbatim DISTANCES ... @@ -63,27 +63,27 @@ In this case you can achieve the same result by using: \verbatim DISTANCES ... - GROUPA=1-10 GROUPB=11-20 + GROUPA=1-10 GROUPB=11-20 MORE_THAN={GAUSSIAN D_0=1.5 R_0=0.00001} ... DISTANCES \endverbatim (see \ref DISTANCES) The advantage of MTRANSFORM_MORE comes, however, if you want to use transformed colvars as input -for \ref MULTICOLVARDENS +for \ref MULTICOLVARDENS */ //+ENDPLUMEDOC //+PLUMEDOC MFILTERS MFILTER_MORE /* -This action can be used to filter the distribution of colvar values in a multicolvar +This action can be used to filter the distribution of colvar values in a multicolvar so that one can compute the mean and so on for only those multicolvars more than a tolerance. This action can be used to create a dynamic group of atom based on the value of a multicolvar. In this action a multicolvar is within the dynamic group if its value is greater than a target. In practise a weight, \f$w_i\f$ is ascribed to each colvar, \f$s_i\f$ calculated by a multicolvar -and this weight measures the degree to which a colvar is a member of the group. This weight is +and this weight measures the degree to which a colvar is a member of the group. This weight is calculated using a \ref switchingfunction , \f$\sigma\f$ so it is given by: \f[ @@ -91,7 +91,7 @@ w_i = 1 - \sigma(s_i) \f] If one calculates a function of the set of multicolvars -these weights are included in the calculation. As such if one calculates the MEAN, \f$\mu\f$ of a filtered +these weights are included in the calculation. As such if one calculates the MEAN, \f$\mu\f$ of a filtered multicolvar what is computed is the following: \f[ @@ -109,10 +109,10 @@ DISTANCES GROUPA=1 GROUPB=2-50 MEAN LABEL=d1 MFILTER_MORE DATA=d1 SWITCH={GAUSSIAN D_0=1.5 R_0=0.00001} MEAN LABEL=d4 \endverbatim -More complicated things can be done by using the label of a filter as input to a new multicolvar as shown -in the example below. Here the coordination numbers of all atoms are computed. The atoms with a coordination +More complicated things can be done by using the label of a filter as input to a new multicolvar as shown +in the example below. Here the coordination numbers of all atoms are computed. The atoms with a coordination number greater than 2 are then identified using the filter. This reduced list of atoms is then used as input -to a second coordination number calculation. This second coordination number thus measures the number of +to a second coordination number calculation. This second coordination number thus measures the number of two-coordinated atoms that each of the two-coordinated atoms is bound to. \verbatim @@ -134,41 +134,41 @@ public: static void registerKeywords( Keywords& keys ); explicit FilterMore(const ActionOptions& ao); double applyFilter( const double& val, double& df ) const ; -}; +}; PLUMED_REGISTER_ACTION(FilterMore,"MFILTER_MORE") PLUMED_REGISTER_ACTION(FilterMore,"MTRANSFORM_MORE") -void FilterMore::registerKeywords( Keywords& keys ){ +void FilterMore::registerKeywords( Keywords& keys ) { MultiColvarFilter::registerKeywords( keys ); keys.add("compulsory","NN","6","The n parameter of the switching function "); keys.add("compulsory","MM","0","The m parameter of the switching function; 0 implies 2*NN"); keys.add("compulsory","D_0","0.0","The d_0 parameter of the switching function"); keys.add("compulsory","R_0","The r_0 parameter of the switching function"); keys.add("optional","SWITCH","This keyword is used if you want to employ an alternative to the continuous swiching function defined above. " - "The following provides information on the \\ref switchingfunction that are available. " - "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); + "The following provides information on the \\ref switchingfunction that are available. " + "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); } FilterMore::FilterMore(const ActionOptions& ao): -Action(ao), -MultiColvarFilter(ao) + Action(ao), + MultiColvarFilter(ao) { // Read in the switching function std::string sw, errors; parse("SWITCH",sw); - if(sw.length()>0){ - sf.set(sw,errors); - if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); + if(sw.length()>0) { + sf.set(sw,errors); + if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); } else { - double r_0=-1.0, d_0; int nn, mm; - parse("NN",nn); parse("MM",mm); - parse("R_0",r_0); parse("D_0",d_0); - if( r_0<0.0 ) error("you must set a value for R_0"); - sf.set(nn,mm,r_0,d_0); + double r_0=-1.0, d_0; int nn, mm; + parse("NN",nn); parse("MM",mm); + parse("R_0",r_0); parse("D_0",d_0); + if( r_0<0.0 ) error("you must set a value for R_0"); + sf.set(nn,mm,r_0,d_0); } log.printf(" filtering colvar values and focussing only on those more than %s\n",( sf.description() ).c_str() ); - checkRead(); + checkRead(); } double FilterMore::applyFilter( const double& val, double& df ) const { diff --git a/src/multicolvar/InPlaneDistances.cpp b/src/multicolvar/InPlaneDistances.cpp index 1801e31bf..d041fa1e0 100644 --- a/src/multicolvar/InPlaneDistances.cpp +++ b/src/multicolvar/InPlaneDistances.cpp @@ -32,14 +32,14 @@ using namespace std; -namespace PLMD{ -namespace multicolvar{ +namespace PLMD { +namespace multicolvar { //+PLUMEDOC MCOLVAR INPLANEDISTANCES /* Calculate distances in the plane perpendicular to an axis -Each quantity calculated in this CV uses the positions of two atoms, this indices of which are specified using the VECTORSTART and VECTOREND keywords, to specify the +Each quantity calculated in this CV uses the positions of two atoms, this indices of which are specified using the VECTORSTART and VECTOREND keywords, to specify the orientation of a vector, \f$\mathbf{n}\f$. The perpendicular distance between this vector and the position of some third atom is then computed using: \f[ x_j = |\mathbf{r}_{j}| \sin (\theta_j) @@ -50,8 +50,8 @@ Keywords such as MORE_THAN and LESS_THAN can then be used to calculate the numbe \par Examples -The following input can be used to calculate the number of atoms that have indices greater than 3 and less than 101 that -are within a cylinder with a radius of 0.3 nm that has its long axis aligned with the vector connecting atoms 1 and 2. +The following input can be used to calculate the number of atoms that have indices greater than 3 and less than 101 that +are within a cylinder with a radius of 0.3 nm that has its long axis aligned with the vector connecting atoms 1 and 2. \verbatim d1: INPLANEDISTANCES VECTORSTART=1 VECTOREND=2 GROUP=3-100 LESS_THAN={RATIONAL D_0=0.2 R_0=0.1} @@ -67,16 +67,16 @@ public: static void registerKeywords( Keywords& keys ); explicit InPlaneDistances(const ActionOptions&); // active methods: - virtual double compute(const unsigned& tindex, AtomValuePack& myatoms ) const ; - bool isPeriodic(){ return false; } + virtual double compute(const unsigned& tindex, AtomValuePack& myatoms ) const ; + bool isPeriodic() { return false; } }; PLUMED_REGISTER_ACTION(InPlaneDistances,"INPLANEDISTANCES") -void InPlaneDistances::registerKeywords( Keywords& keys ){ +void InPlaneDistances::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); keys.use("ALT_MIN"); keys.use("LOWEST"); keys.use("HIGHEST"); - keys.use("MEAN"); keys.use("MIN"); keys.use("MAX"); keys.use("LESS_THAN"); + keys.use("MEAN"); keys.use("MIN"); keys.use("MAX"); keys.use("LESS_THAN"); keys.use("MORE_THAN"); keys.use("BETWEEN"); keys.use("HISTOGRAM"); keys.use("MOMENTS"); keys.add("atoms","VECTORSTART","The first atom position that is used to define the normal to the plane of interest"); keys.add("atoms","VECTOREND","The second atom position that is used to defin the normal to the plane of interest"); @@ -84,8 +84,8 @@ void InPlaneDistances::registerKeywords( Keywords& keys ){ } InPlaneDistances::InPlaneDistances(const ActionOptions&ao): -Action(ao), -MultiColvarBase(ao) + Action(ao), + MultiColvarBase(ao) { // Read in the atoms std::vector<AtomNumber> all_atoms; @@ -99,32 +99,32 @@ MultiColvarBase(ao) // And check everything has been read in correctly checkRead(); - // Now check if we can use link cells +// Now check if we can use link cells bool use_link=false; double rcut; - if( getNumberOfVessels()>0 ){ - vesselbase::LessThan* lt=dynamic_cast<vesselbase::LessThan*>( getPntrToVessel(0) ); - if( lt ){ - use_link=true; rcut=lt->getCutoff(); - } else { - vesselbase::Between* bt=dynamic_cast<vesselbase::Between*>( getPntrToVessel(0) ); - if( bt ) use_link=true; rcut=bt->getCutoff(); - } - if( use_link ){ - for(unsigned i=1;i<getNumberOfVessels();++i){ - vesselbase::LessThan* lt2=dynamic_cast<vesselbase::LessThan*>( getPntrToVessel(i) ); - vesselbase::Between* bt=dynamic_cast<vesselbase::Between*>( getPntrToVessel(i) ); - if( lt2 ){ - double tcut=lt2->getCutoff(); - if( tcut>rcut ) rcut=tcut; - } else if( bt ){ - double tcut=bt->getCutoff(); - if( tcut>rcut ) rcut=tcut; - } else { - use_link=false; - } - } - } - if( use_link ) setLinkCellCutoff( rcut ); + if( getNumberOfVessels()>0 ) { + vesselbase::LessThan* lt=dynamic_cast<vesselbase::LessThan*>( getPntrToVessel(0) ); + if( lt ) { + use_link=true; rcut=lt->getCutoff(); + } else { + vesselbase::Between* bt=dynamic_cast<vesselbase::Between*>( getPntrToVessel(0) ); + if( bt ) use_link=true; rcut=bt->getCutoff(); + } + if( use_link ) { + for(unsigned i=1; i<getNumberOfVessels(); ++i) { + vesselbase::LessThan* lt2=dynamic_cast<vesselbase::LessThan*>( getPntrToVessel(i) ); + vesselbase::Between* bt=dynamic_cast<vesselbase::Between*>( getPntrToVessel(i) ); + if( lt2 ) { + double tcut=lt2->getCutoff(); + if( tcut>rcut ) rcut=tcut; + } else if( bt ) { + double tcut=bt->getCutoff(); + if( tcut>rcut ) rcut=tcut; + } else { + use_link=false; + } + } + } + if( use_link ) setLinkCellCutoff( rcut ); } } @@ -132,7 +132,7 @@ double InPlaneDistances::compute( const unsigned& tindex, AtomValuePack& myatoms Vector normal=getSeparation( myatoms.getPosition(1), myatoms.getPosition(2) ); Vector dir=getSeparation( myatoms.getPosition(1), myatoms.getPosition(0) ); PLMD::Angle a; Vector ddij, ddik; double angle=a.compute(normal,dir,ddij,ddik); - double sangle=sin(angle), cangle=cos(angle); + double sangle=sin(angle), cangle=cos(angle); double dd=dir.modulo(), invdd=1.0/dd, val=dd*sangle; addAtomDerivatives( 1, 0, dd*cangle*ddik + sangle*invdd*dir, myatoms ); diff --git a/src/multicolvar/LocalAverage.cpp b/src/multicolvar/LocalAverage.cpp index 1e1d5c6c0..fdc3e09c4 100644 --- a/src/multicolvar/LocalAverage.cpp +++ b/src/multicolvar/LocalAverage.cpp @@ -29,29 +29,29 @@ Calculate averages over spherical regions centered on atoms As is explained in <a href="http://www.youtube.com/watch?v=iDvZmbWE5ps"> this video </a> certain multicolvars -calculate one scalar quantity or one vector for each of the atoms in the system. For example +calculate one scalar quantity or one vector for each of the atoms in the system. For example \ref COORDINATIONNUMBER measures the coordination number of each of the atoms in the system and \ref Q4 measures the 4th order Steinhardt parameter for each of the atoms in the system. These quantities provide tell us something about the disposition of the atoms in the first coordination sphere of each of the atoms of interest. Lechner and Dellago \cite dellago-q6 have suggested that one can probe local order in a system by taking the average value of such symmetry functions over the atoms within a spherical cutoff of each of these atoms in the systems. When this is done with Steinhardt parameters -they claim this gives a coordinate that is better able to distinguish solid and liquid configurations of Lennard-Jones atoms. +they claim this gives a coordinate that is better able to distinguish solid and liquid configurations of Lennard-Jones atoms. -You can calculate such locally averaged quantities within plumed by using the LOCAL_AVERAGE command. This command calculates +You can calculate such locally averaged quantities within plumed by using the LOCAL_AVERAGE command. This command calculates the following atom-centered quantities: \f[ -s_i = \frac{ c_i + \sum_j \sigma(r_{ij})c_j }{ 1 + \sum_j \sigma(r_{ij}) } +s_i = \frac{ c_i + \sum_j \sigma(r_{ij})c_j }{ 1 + \sum_j \sigma(r_{ij}) } \f] -where the \f$c_i\f$ and \f$c_j\f$ values can be for any one of the symmetry functions that can be calculated using plumed -multicolvars. The function \f$\sigma( r_{ij} )\f$ is a \ref switchingfunction that acts on the distance between +where the \f$c_i\f$ and \f$c_j\f$ values can be for any one of the symmetry functions that can be calculated using plumed +multicolvars. The function \f$\sigma( r_{ij} )\f$ is a \ref switchingfunction that acts on the distance between atoms \f$i\f$ and \f$j\f$. Lechner and Dellago suggest that the parameters of this function should be set so that it the function is equal to one -when atom \f$j\f$ is in the first coordination sphere of atom \f$i\f$ and is zero otherwise. +when atom \f$j\f$ is in the first coordination sphere of atom \f$i\f$ and is zero otherwise. -The \f$s_i\f$ quantities calculated using the above command can be again thought of as atom-centred symmetry functions. They +The \f$s_i\f$ quantities calculated using the above command can be again thought of as atom-centred symmetry functions. They thus operate much like multicolvars. You can thus calculate properties of the distribution of \f$s_i\f$ values using MEAN, LESS_THAN, HISTOGRAM -and so on. You can also probe the value of these averaged variables in regions of the box by using the command in tandem with the +and so on. You can also probe the value of these averaged variables in regions of the box by using the command in tandem with the \ref AROUND command. \par Examples @@ -62,12 +62,12 @@ spherical regions. The number of averaged coordination numbers that are greater \verbatim COORDINATIONNUMBER SPECIES=1-64 D_0=1.3 R_0=0.2 LABEL=d1 LOCAL_AVERAGE ARG=d1 SWITCH={RATIONAL D_0=1.3 R_0=0.2} MORE_THAN={RATIONAL R_0=4} LABEL=la -PRINT ARG=la.* FILE=colvar +PRINT ARG=la.* FILE=colvar \endverbatim -This example input calculates the \f$q_4\f$ (see \ref Q4) vectors for each of the atoms in the system. These vectors are then averaged -component by component over a spherical region. The average value for this quantity is then outputeed to a file. This calculates the -quantities that were used in the paper by Lechner and Dellago \cite dellago-q6 +This example input calculates the \f$q_4\f$ (see \ref Q4) vectors for each of the atoms in the system. These vectors are then averaged +component by component over a spherical region. The average value for this quantity is then outputeed to a file. This calculates the +quantities that were used in the paper by Lechner and Dellago \cite dellago-q6 \verbatim Q4 SPECIES=1-64 SWITCH={RATIONAL D_0=1.3 R_0=0.2} LABEL=q4 @@ -95,49 +95,49 @@ public: /// Actually do the calculation double compute( const unsigned& tindex, AtomValuePack& myatoms ) const ; /// Is the variable periodic - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } }; PLUMED_REGISTER_ACTION(LocalAverage,"LOCAL_AVERAGE") -void LocalAverage::registerKeywords( Keywords& keys ){ +void LocalAverage::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); keys.add("compulsory","NN","6","The n parameter of the switching function "); keys.add("compulsory","MM","0","The m parameter of the switching function; 0 implies 2*NN"); keys.add("compulsory","D_0","0.0","The d_0 parameter of the switching function"); keys.add("compulsory","R_0","The r_0 parameter of the switching function"); keys.add("optional","SWITCH","This keyword is used if you want to employ an alternative to the continuous swiching function defined above. " - "The following provides information on the \\ref switchingfunction that are available. " - "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); + "The following provides information on the \\ref switchingfunction that are available. " + "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); // Use actionWithDistributionKeywords keys.use("SPECIES"); keys.use("SPECIESA"); keys.use("SPECIESB"); keys.remove("LOWMEM"); keys.use("MEAN"); keys.use("MORE_THAN"); keys.use("LESS_THAN"); - keys.use("BETWEEN"); keys.use("HISTOGRAM"); keys.use("MOMENTS"); + keys.use("BETWEEN"); keys.use("HISTOGRAM"); keys.use("MOMENTS"); keys.addFlag("LOWMEM",false,"lower the memory requirements"); if( keys.reserved("VMEAN") ) keys.use("VMEAN"); if( keys.reserved("VSUM") ) keys.use("VSUM"); } LocalAverage::LocalAverage(const ActionOptions& ao): -Action(ao), -MultiColvarBase(ao) + Action(ao), + MultiColvarBase(ao) { if( getNumberOfBaseMultiColvars()>1 ) error("local average with more than one base colvar makes no sense"); // Read in the switching function std::string sw, errors; parse("SWITCH",sw); - if(sw.length()>0){ - switchingFunction.set(sw,errors); + if(sw.length()>0) { + switchingFunction.set(sw,errors); } else { - double r_0=-1.0, d_0; int nn, mm; - parse("NN",nn); parse("MM",mm); - parse("R_0",r_0); parse("D_0",d_0); - if( r_0<0.0 ) error("you must set a value for R_0"); - switchingFunction.set(nn,mm,r_0,d_0); + double r_0=-1.0, d_0; int nn, mm; + parse("NN",nn); parse("MM",mm); + parse("R_0",r_0); parse("D_0",d_0); + if( r_0<0.0 ) error("you must set a value for R_0"); + switchingFunction.set(nn,mm,r_0,d_0); } log.printf(" averaging over central molecule and those within %s\n",( switchingFunction.description() ).c_str() ); rcut2 = switchingFunction.get_dmax()*switchingFunction.get_dmax(); setLinkCellCutoff( switchingFunction.get_dmax() ); - std::vector<AtomNumber> all_atoms; setupMultiColvarBase( all_atoms ); + std::vector<AtomNumber> all_atoms; setupMultiColvarBase( all_atoms ); } unsigned LocalAverage::getNumberOfQuantities() const { @@ -146,113 +146,113 @@ unsigned LocalAverage::getNumberOfQuantities() const { double LocalAverage::compute( const unsigned& tindex, AtomValuePack& myatoms ) const { double d2, sw, dfunc; MultiValue& myvals = myatoms.getUnderlyingMultiValue(); - std::vector<double> values( getBaseMultiColvar(0)->getNumberOfQuantities() ); + std::vector<double> values( getBaseMultiColvar(0)->getNumberOfQuantities() ); getInputData( 0, false, myatoms, values ); myvals.addTemporyValue( values[0] ); - if( values.size()>2 ){ - for(unsigned j=2;j<values.size();++j) myatoms.addValue( j, values[0]*values[j] ); + if( values.size()>2 ) { + for(unsigned j=2; j<values.size(); ++j) myatoms.addValue( j, values[0]*values[j] ); } else { - myatoms.addValue( 1, values[0]*values[1] ); + myatoms.addValue( 1, values[0]*values[1] ); } - if( !doNotCalculateDerivatives() ){ - MultiValue& myder=getInputDerivatives( 0, false, myatoms ); - if( values.size()>2 ){ - for(unsigned j=0;j<myder.getNumberActive();++j){ - unsigned jder=myder.getActiveIndex(j); - for(unsigned k=2;k<values.size();++k){ - myatoms.addDerivative( k, jder, values[0]*myder.getDerivative(k,jder) ); - myatoms.addDerivative( k, jder, values[k]*myder.getDerivative(0,jder) ); - } - } - } else { - for(unsigned j=0;j<myder.getNumberActive();++j){ - unsigned jder=myder.getActiveIndex(j); - myatoms.addDerivative( 1, jder, values[0]*myder.getDerivative(1,jder) ); - myatoms.addDerivative( 1, jder, values[1]*myder.getDerivative(0,jder) ); - } + if( !doNotCalculateDerivatives() ) { + MultiValue& myder=getInputDerivatives( 0, false, myatoms ); + if( values.size()>2 ) { + for(unsigned j=0; j<myder.getNumberActive(); ++j) { + unsigned jder=myder.getActiveIndex(j); + for(unsigned k=2; k<values.size(); ++k) { + myatoms.addDerivative( k, jder, values[0]*myder.getDerivative(k,jder) ); + myatoms.addDerivative( k, jder, values[k]*myder.getDerivative(0,jder) ); + } } - for(unsigned j=0;j<myder.getNumberActive();++j){ - unsigned jder=myder.getActiveIndex(j); myvals.addTemporyDerivative( jder, myder.getDerivative(0, jder) ); + } else { + for(unsigned j=0; j<myder.getNumberActive(); ++j) { + unsigned jder=myder.getActiveIndex(j); + myatoms.addDerivative( 1, jder, values[0]*myder.getDerivative(1,jder) ); + myatoms.addDerivative( 1, jder, values[1]*myder.getDerivative(0,jder) ); } - myder.clearAll(); + } + for(unsigned j=0; j<myder.getNumberActive(); ++j) { + unsigned jder=myder.getActiveIndex(j); myvals.addTemporyDerivative( jder, myder.getDerivative(0, jder) ); + } + myder.clearAll(); } - - for(unsigned i=1;i<myatoms.getNumberOfAtoms();++i){ - Vector& distance=myatoms.getPosition(i); // getSeparation( myatoms.getPosition(0), myatoms.getPosition(i) ); - if ( (d2=distance[0]*distance[0])<rcut2 && - (d2+=distance[1]*distance[1])<rcut2 && - (d2+=distance[2]*distance[2])<rcut2) { - - sw = switchingFunction.calculateSqr( d2, dfunc ); - - getInputData( i, false, myatoms, values ); - if( values.size()>2 ){ - for(unsigned j=2;j<values.size();++j) myatoms.addValue( j, sw*values[0]*values[j] ); - } else { - myatoms.addValue( 1, sw*values[0]*values[1] ); - } - myvals.addTemporyValue(sw); - - if( !doNotCalculateDerivatives() ){ - Tensor vir(distance,distance); - MultiValue& myder=getInputDerivatives( i, false, myatoms ); - if( values.size()>2 ){ - for(unsigned j=0;j<myder.getNumberActive();++j){ - unsigned jder=myder.getActiveIndex(j); - for(unsigned k=2;k<values.size();++k){ - myatoms.addDerivative( k, jder, sw*values[0]*myder.getDerivative(k,jder) ); - myatoms.addDerivative( k, jder, sw*values[k]*myder.getDerivative(0,jder) ); - } - } - for(unsigned k=2;k<values.size();++k){ - addAtomDerivatives( k, 0, (-dfunc)*values[0]*values[k]*distance, myatoms ); - addAtomDerivatives( k, i, (+dfunc)*values[0]*values[k]*distance, myatoms ); - myatoms.addBoxDerivatives( k, (-dfunc)*values[0]*values[k]*vir ); - } - } else { - for(unsigned j=0;j<myder.getNumberActive();++j){ - unsigned jder=myder.getActiveIndex(j); - myatoms.addDerivative( 1, jder, sw*values[0]*myder.getDerivative(1,jder) ); - myatoms.addDerivative( 1, jder, sw*values[1]*myder.getDerivative(0,jder) ); - } - addAtomDerivatives( 1, 0, (-dfunc)*values[0]*values[1]*distance, myatoms ); - addAtomDerivatives( 1, i, (+dfunc)*values[0]*values[1]*distance, myatoms ); - myatoms.addBoxDerivatives( 1, (-dfunc)*values[0]*values[1]*vir ); - } - // And the bit we use to average the vector - addAtomDerivatives( -1, 0, (-dfunc)*values[0]*distance, myatoms ); - addAtomDerivatives( -1, i, (+dfunc)*values[0]*distance, myatoms ); - for(unsigned j=0;j<myder.getNumberActive();++j){ - unsigned jder=myder.getActiveIndex(j); myvals.addTemporyDerivative( jder, sw*myder.getDerivative(0, jder) ); - } - myatoms.addTemporyBoxDerivatives( (-dfunc)*values[0]*vir ); - myder.clearAll(); - } - } + + for(unsigned i=1; i<myatoms.getNumberOfAtoms(); ++i) { + Vector& distance=myatoms.getPosition(i); // getSeparation( myatoms.getPosition(0), myatoms.getPosition(i) ); + if ( (d2=distance[0]*distance[0])<rcut2 && + (d2+=distance[1]*distance[1])<rcut2 && + (d2+=distance[2]*distance[2])<rcut2) { + + sw = switchingFunction.calculateSqr( d2, dfunc ); + + getInputData( i, false, myatoms, values ); + if( values.size()>2 ) { + for(unsigned j=2; j<values.size(); ++j) myatoms.addValue( j, sw*values[0]*values[j] ); + } else { + myatoms.addValue( 1, sw*values[0]*values[1] ); + } + myvals.addTemporyValue(sw); + + if( !doNotCalculateDerivatives() ) { + Tensor vir(distance,distance); + MultiValue& myder=getInputDerivatives( i, false, myatoms ); + if( values.size()>2 ) { + for(unsigned j=0; j<myder.getNumberActive(); ++j) { + unsigned jder=myder.getActiveIndex(j); + for(unsigned k=2; k<values.size(); ++k) { + myatoms.addDerivative( k, jder, sw*values[0]*myder.getDerivative(k,jder) ); + myatoms.addDerivative( k, jder, sw*values[k]*myder.getDerivative(0,jder) ); + } + } + for(unsigned k=2; k<values.size(); ++k) { + addAtomDerivatives( k, 0, (-dfunc)*values[0]*values[k]*distance, myatoms ); + addAtomDerivatives( k, i, (+dfunc)*values[0]*values[k]*distance, myatoms ); + myatoms.addBoxDerivatives( k, (-dfunc)*values[0]*values[k]*vir ); + } + } else { + for(unsigned j=0; j<myder.getNumberActive(); ++j) { + unsigned jder=myder.getActiveIndex(j); + myatoms.addDerivative( 1, jder, sw*values[0]*myder.getDerivative(1,jder) ); + myatoms.addDerivative( 1, jder, sw*values[1]*myder.getDerivative(0,jder) ); + } + addAtomDerivatives( 1, 0, (-dfunc)*values[0]*values[1]*distance, myatoms ); + addAtomDerivatives( 1, i, (+dfunc)*values[0]*values[1]*distance, myatoms ); + myatoms.addBoxDerivatives( 1, (-dfunc)*values[0]*values[1]*vir ); + } + // And the bit we use to average the vector + addAtomDerivatives( -1, 0, (-dfunc)*values[0]*distance, myatoms ); + addAtomDerivatives( -1, i, (+dfunc)*values[0]*distance, myatoms ); + for(unsigned j=0; j<myder.getNumberActive(); ++j) { + unsigned jder=myder.getActiveIndex(j); myvals.addTemporyDerivative( jder, sw*myder.getDerivative(0, jder) ); + } + myatoms.addTemporyBoxDerivatives( (-dfunc)*values[0]*vir ); + myder.clearAll(); + } + } } // Set the tempory weight updateActiveAtoms( myatoms ); - if( values.size()>2){ - double norm=0; - for(unsigned i=2;i<values.size();++i){ - myvals.quotientRule( i, i ); - // Calculate length of vector - norm+=myvals.get(i)*myvals.get(i); - } - norm=sqrt(norm); myatoms.setValue(1, norm); double inorm = 1.0 / norm; - for(unsigned j=0;j<myvals.getNumberActive();++j){ - unsigned jder=myvals.getActiveIndex(j); - for(unsigned i=2;i<values.size();++i){ - myvals.addDerivative( 1, jder, myvals.get(i)*inorm*myvals.getDerivative(i,jder) ); - } + if( values.size()>2) { + double norm=0; + for(unsigned i=2; i<values.size(); ++i) { + myvals.quotientRule( i, i ); + // Calculate length of vector + norm+=myvals.get(i)*myvals.get(i); + } + norm=sqrt(norm); myatoms.setValue(1, norm); double inorm = 1.0 / norm; + for(unsigned j=0; j<myvals.getNumberActive(); ++j) { + unsigned jder=myvals.getActiveIndex(j); + for(unsigned i=2; i<values.size(); ++i) { + myvals.addDerivative( 1, jder, myvals.get(i)*inorm*myvals.getDerivative(i,jder) ); } + } } else { - myvals.quotientRule( 1, 1 ); + myvals.quotientRule( 1, 1 ); } - + return myatoms.getValue(1); } diff --git a/src/multicolvar/MultiColvarBase.cpp b/src/multicolvar/MultiColvarBase.cpp index 201be8e0e..2353daa6d 100644 --- a/src/multicolvar/MultiColvarBase.cpp +++ b/src/multicolvar/MultiColvarBase.cpp @@ -33,17 +33,17 @@ using namespace std; -namespace PLMD{ -namespace multicolvar{ +namespace PLMD { +namespace multicolvar { -void MultiColvarBase::registerKeywords( Keywords& keys ){ +void MultiColvarBase::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionWithValue::registerKeywords( keys ); ActionAtomistic::registerKeywords( keys ); keys.addFlag("NOPBC",false,"ignore the periodic boundary conditions when calculating distances"); ActionWithVessel::registerKeywords( keys ); keys.add("hidden","NL_STRIDE","the frequency with which the neighbor list should be updated. Between neighbour list update steps all quantities " - "that contributed less than TOL at the previous neighbor list update step are ignored."); + "that contributed less than TOL at the previous neighbor list update step are ignored."); keys.setComponentsIntroduction("When the label of this action is used as the input for a second you are not referring to a scalar quantity as you are in " "regular collective variables. The label is used to reference the full set of quantities calculated by " "the action. This is usual when using \\ref multicolvarfunction. Generally when doing this the previously calculated " @@ -58,439 +58,439 @@ void MultiColvarBase::registerKeywords( Keywords& keys ){ "made the label of the components customizable. As such by using the LABEL keyword in the description of the keyword " "input you can customize the component name"); keys.reserve("atoms-3","SPECIES","this keyword is used for colvars such as coordination number. In that context it specifies that plumed should calculate " - "one coordination number for each of the atoms specified. Each of these coordination numbers specifies how many of the " - "other specified atoms are within a certain cutoff of the central atom. You can specify the atoms here as another multicolvar " - "action or using a MultiColvarFilter or ActionVolume action. When you do so the quantity is calculated for those atoms specified " - "in the previous multicolvar. This is useful if you would like to calculate the Steinhardt parameter for those atoms that have a " - "coordination number more than four for example"); + "one coordination number for each of the atoms specified. Each of these coordination numbers specifies how many of the " + "other specified atoms are within a certain cutoff of the central atom. You can specify the atoms here as another multicolvar " + "action or using a MultiColvarFilter or ActionVolume action. When you do so the quantity is calculated for those atoms specified " + "in the previous multicolvar. This is useful if you would like to calculate the Steinhardt parameter for those atoms that have a " + "coordination number more than four for example"); keys.reserve("atoms-4","SPECIESA","this keyword is used for colvars such as the coordination number. In that context it species that plumed should calculate " - "one coordination number for each of the atoms specified in SPECIESA. Each of these cooordination numbers specifies how many " - "of the atoms specifies using SPECIESB is within the specified cutoff. As with the species keyword the input can also be specified " - "using the label of another multicolvar"); + "one coordination number for each of the atoms specified in SPECIESA. Each of these cooordination numbers specifies how many " + "of the atoms specifies using SPECIESB is within the specified cutoff. As with the species keyword the input can also be specified " + "using the label of another multicolvar"); keys.reserve("atoms-4","SPECIESB","this keyword is used for colvars such as the coordination number. It must appear with SPECIESA. For a full explanation see " - "the documentation for that keyword"); -} + "the documentation for that keyword"); +} MultiColvarBase::MultiColvarBase(const ActionOptions&ao): -Action(ao), -ActionAtomistic(ao), -ActionWithValue(ao), -ActionWithVessel(ao), -usepbc(false), -allthirdblockintasks(false), -uselinkforthree(false), -linkcells(comm), -threecells(comm), -setup_completed(false), -atomsWereRetrieved(false), -matsums(false), -usespecies(false), -nblock(0) + Action(ao), + ActionAtomistic(ao), + ActionWithValue(ao), + ActionWithVessel(ao), + usepbc(false), + allthirdblockintasks(false), + uselinkforthree(false), + linkcells(comm), + threecells(comm), + setup_completed(false), + atomsWereRetrieved(false), + matsums(false), + usespecies(false), + nblock(0) { - if( keywords.exists("NOPBC") ){ - bool nopbc=!usepbc; parseFlag("NOPBC",nopbc); - usepbc=!nopbc; - } - if( keywords.exists("SPECIESA") ){ matsums=usespecies=true; } + if( keywords.exists("NOPBC") ) { + bool nopbc=!usepbc; parseFlag("NOPBC",nopbc); + usepbc=!nopbc; + } + if( keywords.exists("SPECIESA") ) { matsums=usespecies=true; } } -void MultiColvarBase::readAtomsLikeKeyword( const std::string & key, const int& natoms, std::vector<AtomNumber>& all_atoms ){ +void MultiColvarBase::readAtomsLikeKeyword( const std::string & key, const int& natoms, std::vector<AtomNumber>& all_atoms ) { plumed_assert( !usespecies ); if( all_atoms.size()>0 ) return; std::vector<AtomNumber> t; - for(int i=1;;++i ){ - parseAtomList(key, i, t ); - if( t.empty() ) break; - - log.printf(" Colvar %d is calculated from atoms : ", i); - for(unsigned j=0;j<t.size();++j) log.printf("%d ",t[j].serial() ); - log.printf("\n"); - - if( i==1 && natoms<0 ){ ablocks.resize(t.size()); } - else if( i==1 ) ablocks.resize(natoms); - if( t.size()!=ablocks.size() ){ - std::string ss; Tools::convert(i,ss); - error(key + ss + " keyword has the wrong number of atoms"); - } - for(unsigned j=0;j<ablocks.size();++j){ - ablocks[j].push_back( ablocks.size()*(i-1)+j ); all_atoms.push_back( t[j] ); - atom_lab.push_back( std::pair<unsigned,unsigned>( 0, ablocks.size()*(i-1)+j ) ); - } - t.resize(0); + for(int i=1;; ++i ) { + parseAtomList(key, i, t ); + if( t.empty() ) break; + + log.printf(" Colvar %d is calculated from atoms : ", i); + for(unsigned j=0; j<t.size(); ++j) log.printf("%d ",t[j].serial() ); + log.printf("\n"); + + if( i==1 && natoms<0 ) { ablocks.resize(t.size()); } + else if( i==1 ) ablocks.resize(natoms); + if( t.size()!=ablocks.size() ) { + std::string ss; Tools::convert(i,ss); + error(key + ss + " keyword has the wrong number of atoms"); + } + for(unsigned j=0; j<ablocks.size(); ++j) { + ablocks[j].push_back( ablocks.size()*(i-1)+j ); all_atoms.push_back( t[j] ); + atom_lab.push_back( std::pair<unsigned,unsigned>( 0, ablocks.size()*(i-1)+j ) ); + } + t.resize(0); } - if( all_atoms.size()>0 ){ - nblock=0; - for(unsigned i=0;i<ablocks[0].size();++i) addTaskToList( i ); + if( all_atoms.size()>0 ) { + nblock=0; + for(unsigned i=0; i<ablocks[0].size(); ++i) addTaskToList( i ); } } -bool MultiColvarBase::parseMultiColvarAtomList(const std::string& key, const int& num, std::vector<AtomNumber>& t){ - std::vector<std::string> mlabs; +bool MultiColvarBase::parseMultiColvarAtomList(const std::string& key, const int& num, std::vector<AtomNumber>& t) { + std::vector<std::string> mlabs; if( num<0 ) parseVector(key,mlabs); else parseNumberedVector(key,num,mlabs); if( mlabs.size()==0 ) return false; std::string mname; unsigned found_mcolv=mlabs.size(); - for(unsigned i=0;i<mlabs.size();++i){ - MultiColvarBase* mycolv = plumed.getActionSet().selectWithLabel<MultiColvarBase*>(mlabs[i]); - if(!mycolv){ found_mcolv=i; break; } - // Check all base multicolvars are of same type - if( i==0 ){ - mname = mycolv->getName(); - if( mycolv->isPeriodic() ) error("multicolvar functions don't work with this multicolvar"); - } else { - if( mname!=mycolv->getName() ) error("All input multicolvars must be of same type"); - } - // And track which variable stores each colvar - for(unsigned j=0;j<mycolv->getFullNumberOfTasks();++j) atom_lab.push_back( std::pair<unsigned,unsigned>( mybasemulticolvars.size()+1, j ) ); - // And store the multicolvar base - mybasemulticolvars.push_back( mycolv ); - // And create a basedata stash - mybasedata.push_back( mybasemulticolvars[mybasemulticolvars.size()-1]->buildDataStashes( this ) ); - // Check if weight has derivatives - if( mybasemulticolvars[ mybasemulticolvars.size()-1 ]->weightHasDerivatives ) weightHasDerivatives=true; - plumed_assert( mybasemulticolvars.size()==mybasedata.size() ); + for(unsigned i=0; i<mlabs.size(); ++i) { + MultiColvarBase* mycolv = plumed.getActionSet().selectWithLabel<MultiColvarBase*>(mlabs[i]); + if(!mycolv) { found_mcolv=i; break; } + // Check all base multicolvars are of same type + if( i==0 ) { + mname = mycolv->getName(); + if( mycolv->isPeriodic() ) error("multicolvar functions don't work with this multicolvar"); + } else { + if( mname!=mycolv->getName() ) error("All input multicolvars must be of same type"); + } + // And track which variable stores each colvar + for(unsigned j=0; j<mycolv->getFullNumberOfTasks(); ++j) atom_lab.push_back( std::pair<unsigned,unsigned>( mybasemulticolvars.size()+1, j ) ); + // And store the multicolvar base + mybasemulticolvars.push_back( mycolv ); + // And create a basedata stash + mybasedata.push_back( mybasemulticolvars[mybasemulticolvars.size()-1]->buildDataStashes( this ) ); + // Check if weight has derivatives + if( mybasemulticolvars[ mybasemulticolvars.size()-1 ]->weightHasDerivatives ) weightHasDerivatives=true; + plumed_assert( mybasemulticolvars.size()==mybasedata.size() ); } // Have we conventional atoms to read in - if( found_mcolv==0 ){ - std::vector<AtomNumber> tt; ActionAtomistic::interpretAtomList( mlabs, tt ); - for(unsigned i=0;i<tt.size();++i){ atom_lab.push_back( std::pair<unsigned,unsigned>( 0, t.size() + i ) ); } - log.printf(" keyword %s takes atoms : ", key.c_str() ); - for(unsigned i=0;i<tt.size();++i){ t.push_back( tt[i] ); log.printf("%d ",tt[i].serial() ); } - log.printf("\n"); - } else if( found_mcolv==mlabs.size() ){ - if( checkNumericalDerivatives() ) error("cannot use NUMERICAL_DERIVATIVES keyword with dynamic groups as input"); - log.printf(" keyword %s takes dynamic groups of atoms constructed from multicolvars labelled : ", key.c_str() ); - for(unsigned i=0;i<mlabs.size();++i) log.printf("%s ",mlabs[i].c_str() ); - log.printf("\n"); + if( found_mcolv==0 ) { + std::vector<AtomNumber> tt; ActionAtomistic::interpretAtomList( mlabs, tt ); + for(unsigned i=0; i<tt.size(); ++i) { atom_lab.push_back( std::pair<unsigned,unsigned>( 0, t.size() + i ) ); } + log.printf(" keyword %s takes atoms : ", key.c_str() ); + for(unsigned i=0; i<tt.size(); ++i) { t.push_back( tt[i] ); log.printf("%d ",tt[i].serial() ); } + log.printf("\n"); + } else if( found_mcolv==mlabs.size() ) { + if( checkNumericalDerivatives() ) error("cannot use NUMERICAL_DERIVATIVES keyword with dynamic groups as input"); + log.printf(" keyword %s takes dynamic groups of atoms constructed from multicolvars labelled : ", key.c_str() ); + for(unsigned i=0; i<mlabs.size(); ++i) log.printf("%s ",mlabs[i].c_str() ); + log.printf("\n"); } else if( found_mcolv<mlabs.size() ) { - error("cannot mix multicolvar input and atom input in one line"); + error("cannot mix multicolvar input and atom input in one line"); } return true; } -void MultiColvarBase::readTwoGroups( const std::string& key0, const std::string& key1, const std::string& key2, std::vector<AtomNumber>& all_atoms ){ +void MultiColvarBase::readTwoGroups( const std::string& key0, const std::string& key1, const std::string& key2, std::vector<AtomNumber>& all_atoms ) { plumed_dbg_assert( keywords.exists(key0) && keywords.exists(key1) && keywords.exists(key2) ); ablocks.resize( 2 ); - if( parseMultiColvarAtomList(key0,-1,all_atoms) ){ - nblock=atom_lab.size(); for(unsigned i=0;i<2;++i) ablocks[i].resize(nblock); - resizeBookeepingArray( nblock, nblock ); - for(unsigned i=0;i<nblock;++i) ablocks[0][i]=ablocks[1][i]=i; - for(unsigned i=1;i<nblock;++i){ - for(unsigned j=0;j<i;++j){ - bookeeping(i,j).first=getFullNumberOfTasks(); - addTaskToList( i*nblock + j ); - bookeeping(i,j).second=getFullNumberOfTasks(); - } - } + if( parseMultiColvarAtomList(key0,-1,all_atoms) ) { + nblock=atom_lab.size(); for(unsigned i=0; i<2; ++i) ablocks[i].resize(nblock); + resizeBookeepingArray( nblock, nblock ); + for(unsigned i=0; i<nblock; ++i) ablocks[0][i]=ablocks[1][i]=i; + for(unsigned i=1; i<nblock; ++i) { + for(unsigned j=0; j<i; ++j) { + bookeeping(i,j).first=getFullNumberOfTasks(); + addTaskToList( i*nblock + j ); + bookeeping(i,j).second=getFullNumberOfTasks(); + } + } } else { - parseMultiColvarAtomList(key1,-1,all_atoms); - ablocks[0].resize( atom_lab.size() ); for(unsigned i=0;i<ablocks[0].size();++i) ablocks[0][i]=i; - parseMultiColvarAtomList(key2,-1,all_atoms); - ablocks[1].resize( atom_lab.size() - ablocks[0].size() ); for(unsigned i=0;i<ablocks[1].size();++i) ablocks[1][i]=ablocks[0].size() + i; - - if( ablocks[0].size()>ablocks[1].size() ) nblock = ablocks[0].size(); - else nblock=ablocks[1].size(); - - resizeBookeepingArray( ablocks[0].size(), ablocks[1].size() ); - for(unsigned i=0;i<ablocks[0].size();++i){ - for(unsigned j=0;j<ablocks[1].size();++j){ - bookeeping(i,j).first=getFullNumberOfTasks(); - if( atom_lab[ablocks[0][i]].first>0 && atom_lab[ablocks[1][j]].first>0 ){ - if( mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel() && - atom_lab[ablocks[0][i]].second!=atom_lab[ablocks[1][j]].second ) addTaskToList( i*nblock + j ); - } else if( all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[1][j]].second] ) addTaskToList( i*nblock + j ); - bookeeping(i,j).second=getFullNumberOfTasks(); - } + parseMultiColvarAtomList(key1,-1,all_atoms); + ablocks[0].resize( atom_lab.size() ); for(unsigned i=0; i<ablocks[0].size(); ++i) ablocks[0][i]=i; + parseMultiColvarAtomList(key2,-1,all_atoms); + ablocks[1].resize( atom_lab.size() - ablocks[0].size() ); for(unsigned i=0; i<ablocks[1].size(); ++i) ablocks[1][i]=ablocks[0].size() + i; + + if( ablocks[0].size()>ablocks[1].size() ) nblock = ablocks[0].size(); + else nblock=ablocks[1].size(); + + resizeBookeepingArray( ablocks[0].size(), ablocks[1].size() ); + for(unsigned i=0; i<ablocks[0].size(); ++i) { + for(unsigned j=0; j<ablocks[1].size(); ++j) { + bookeeping(i,j).first=getFullNumberOfTasks(); + if( atom_lab[ablocks[0][i]].first>0 && atom_lab[ablocks[1][j]].first>0 ) { + if( mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel() && + atom_lab[ablocks[0][i]].second!=atom_lab[ablocks[1][j]].second ) addTaskToList( i*nblock + j ); + } else if( all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[1][j]].second] ) addTaskToList( i*nblock + j ); + bookeeping(i,j).second=getFullNumberOfTasks(); } + } } } -void MultiColvarBase::readGroupKeywords( const std::string& key0, const std::string& key1, const std::string& key2, const std::string& key3, - const bool& no_third_dim_accum, const bool& symmetric, std::vector<AtomNumber>& all_atoms ){ +void MultiColvarBase::readGroupKeywords( const std::string& key0, const std::string& key1, const std::string& key2, const std::string& key3, + const bool& no_third_dim_accum, const bool& symmetric, std::vector<AtomNumber>& all_atoms ) { plumed_dbg_assert( keywords.exists(key0) && keywords.exists(key1) && keywords.exists(key2) && keywords.exists(key3) ); ablocks.resize( 3 ); - if( parseMultiColvarAtomList(key0,-1,all_atoms) ){ - if( no_third_dim_accum ){ - nblock=atom_lab.size(); ablocks[0].resize(nblock); ablocks[1].resize( nblock ); - for(unsigned i=0;i<ablocks[0].size();++i) ablocks[0][i]=ablocks[1][i]=i; - resizeBookeepingArray( nblock, nblock ); - if( symmetric ){ - // This ensures that later parts of the code don't switch off allthirdblockintasks - for(unsigned i=0;i<nblock;++i){ bookeeping(i,i).first=0; bookeeping(i,i).second=1; } - for(unsigned i=1;i<nblock;++i){ - for(unsigned j=0;j<i;++j){ - bookeeping(j,i).first=bookeeping(i,j).first=getFullNumberOfTasks(); - addTaskToList( i*nblock + j ); - bookeeping(j,i).second=bookeeping(i,j).second=getFullNumberOfTasks(); - } - } - } else { - for(unsigned i=0;i<nblock;++i){ - for(unsigned j=0;j<nblock;++j){ - if( i==j ) continue ; - bookeeping(i,j).first=getFullNumberOfTasks(); - addTaskToList( i*nblock + j ); - bookeeping(i,j).second=getFullNumberOfTasks(); - } - } + if( parseMultiColvarAtomList(key0,-1,all_atoms) ) { + if( no_third_dim_accum ) { + nblock=atom_lab.size(); ablocks[0].resize(nblock); ablocks[1].resize( nblock ); + for(unsigned i=0; i<ablocks[0].size(); ++i) ablocks[0][i]=ablocks[1][i]=i; + resizeBookeepingArray( nblock, nblock ); + if( symmetric ) { + // This ensures that later parts of the code don't switch off allthirdblockintasks + for(unsigned i=0; i<nblock; ++i) { bookeeping(i,i).first=0; bookeeping(i,i).second=1; } + for(unsigned i=1; i<nblock; ++i) { + for(unsigned j=0; j<i; ++j) { + bookeeping(j,i).first=bookeeping(i,j).first=getFullNumberOfTasks(); + addTaskToList( i*nblock + j ); + bookeeping(j,i).second=bookeeping(i,j).second=getFullNumberOfTasks(); } - if( !parseMultiColvarAtomList(key3,-1,all_atoms) ) error("missing required keyword " + key3 + " in input"); - ablocks[2].resize( atom_lab.size() - ablocks[0].size() ); - for(unsigned i=0;i<ablocks[2].size();++i) ablocks[2][i]=ablocks[0].size() + i; + } } else { - nblock=atom_lab.size(); for(unsigned i=0;i<3;++i) ablocks[i].resize(nblock); - resizeBookeepingArray( nblock, nblock ); - for(unsigned i=0;i<nblock;++i){ ablocks[0][i]=i; ablocks[1][i]=i; ablocks[2][i]=i; } - if( symmetric ){ - for(unsigned i=2;i<nblock;++i){ - for(unsigned j=1;j<i;++j){ - bookeeping(i,j).first=getFullNumberOfTasks(); - for(unsigned k=0;k<j;++k) addTaskToList( i*nblock*nblock + j*nblock + k ); - bookeeping(i,j).second=getFullNumberOfTasks(); - } - } - } else { - for(unsigned i=0;i<nblock;++i){ - for(unsigned j=0;j<nblock;++j){ - if( i==j ) continue; - bookeeping(i,j).first=getFullNumberOfTasks(); - for(unsigned k=0;k<nblock;++k){ - if( i!=k && j!=k ) addTaskToList( i*nblock*nblock + j*nblock + k ); - } - bookeeping(i,j).first=getFullNumberOfTasks(); - } - } + for(unsigned i=0; i<nblock; ++i) { + for(unsigned j=0; j<nblock; ++j) { + if( i==j ) continue ; + bookeeping(i,j).first=getFullNumberOfTasks(); + addTaskToList( i*nblock + j ); + bookeeping(i,j).second=getFullNumberOfTasks(); + } + } + } + if( !parseMultiColvarAtomList(key3,-1,all_atoms) ) error("missing required keyword " + key3 + " in input"); + ablocks[2].resize( atom_lab.size() - ablocks[0].size() ); + for(unsigned i=0; i<ablocks[2].size(); ++i) ablocks[2][i]=ablocks[0].size() + i; + } else { + nblock=atom_lab.size(); for(unsigned i=0; i<3; ++i) ablocks[i].resize(nblock); + resizeBookeepingArray( nblock, nblock ); + for(unsigned i=0; i<nblock; ++i) { ablocks[0][i]=i; ablocks[1][i]=i; ablocks[2][i]=i; } + if( symmetric ) { + for(unsigned i=2; i<nblock; ++i) { + for(unsigned j=1; j<i; ++j) { + bookeeping(i,j).first=getFullNumberOfTasks(); + for(unsigned k=0; k<j; ++k) addTaskToList( i*nblock*nblock + j*nblock + k ); + bookeeping(i,j).second=getFullNumberOfTasks(); + } + } + } else { + for(unsigned i=0; i<nblock; ++i) { + for(unsigned j=0; j<nblock; ++j) { + if( i==j ) continue; + bookeeping(i,j).first=getFullNumberOfTasks(); + for(unsigned k=0; k<nblock; ++k) { + if( i!=k && j!=k ) addTaskToList( i*nblock*nblock + j*nblock + k ); + } + bookeeping(i,j).first=getFullNumberOfTasks(); } + } } + } } else { - readThreeGroups( key1, key2, key3, true, no_third_dim_accum, all_atoms ); + readThreeGroups( key1, key2, key3, true, no_third_dim_accum, all_atoms ); } } -void MultiColvarBase::readThreeGroups( const std::string& key1, const std::string& key2, const std::string& key3, - const bool& allow2, const bool& no_third_dim_accum, std::vector<AtomNumber>& all_atoms ){ +void MultiColvarBase::readThreeGroups( const std::string& key1, const std::string& key2, const std::string& key3, + const bool& allow2, const bool& no_third_dim_accum, std::vector<AtomNumber>& all_atoms ) { plumed_dbg_assert( keywords.exists(key1) && keywords.exists(key2) && keywords.exists(key3) ); ablocks.resize( 3 ); bool readkey1=parseMultiColvarAtomList(key1,-1,all_atoms); - ablocks[0].resize( atom_lab.size() ); for(unsigned i=0;i<ablocks[0].size();++i) ablocks[0][i]=i; + ablocks[0].resize( atom_lab.size() ); for(unsigned i=0; i<ablocks[0].size(); ++i) ablocks[0][i]=i; bool readkey2=parseMultiColvarAtomList(key2,-1,all_atoms); if( !readkey1 && !readkey2 ) return ; - ablocks[1].resize( atom_lab.size() - ablocks[0].size() ); for(unsigned i=0;i<ablocks[1].size();++i) ablocks[1][i]=ablocks[0].size() + i; + ablocks[1].resize( atom_lab.size() - ablocks[0].size() ); for(unsigned i=0; i<ablocks[1].size(); ++i) ablocks[1][i]=ablocks[0].size() + i; resizeBookeepingArray( ablocks[0].size(), ablocks[1].size() ); bool readkey3=parseMultiColvarAtomList(key3,-1,all_atoms); - if( !readkey3 && !allow2 ){ - error("missing atom specification " + key3); - } else if( !readkey3 ){ - if( ablocks[1].size()>ablocks[0].size() ) nblock=ablocks[1].size(); - else nblock=ablocks[0].size(); - - ablocks[2].resize( ablocks[1].size() ); - for(unsigned i=0;i<ablocks[1].size();++i) ablocks[2][i]=ablocks[0].size() + i; - for(unsigned i=0;i<ablocks[0].size();++i){ - for(unsigned j=1;j<ablocks[1].size();++j){ - bookeeping(i,j).first=getFullNumberOfTasks(); - for(unsigned k=0;k<j;++k){ - if( atom_lab[ablocks[0][i]].first>0 && atom_lab[ablocks[1][j]].first>0 && atom_lab[ablocks[2][k]].first>0 ){ - if( mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel() && - mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() && - mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() && - atom_lab[ablocks[0][i]].second!=atom_lab[ablocks[1][j]].second && atom_lab[ablocks[0][i]].second!=atom_lab[ablocks[2][k]].second && - atom_lab[ablocks[1][j]].second!=atom_lab[ablocks[2][k]].second ) addTaskToList( nblock*nblock*i + nblock*j + k ); - } else if( all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[1][j]].second] && - all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] && - all_atoms[atom_lab[ablocks[1][j]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] ) addTaskToList( nblock*nblock*i + nblock*j + k ); - } - bookeeping(i,j).second=getFullNumberOfTasks(); + if( !readkey3 && !allow2 ) { + error("missing atom specification " + key3); + } else if( !readkey3 ) { + if( ablocks[1].size()>ablocks[0].size() ) nblock=ablocks[1].size(); + else nblock=ablocks[0].size(); + + ablocks[2].resize( ablocks[1].size() ); + for(unsigned i=0; i<ablocks[1].size(); ++i) ablocks[2][i]=ablocks[0].size() + i; + for(unsigned i=0; i<ablocks[0].size(); ++i) { + for(unsigned j=1; j<ablocks[1].size(); ++j) { + bookeeping(i,j).first=getFullNumberOfTasks(); + for(unsigned k=0; k<j; ++k) { + if( atom_lab[ablocks[0][i]].first>0 && atom_lab[ablocks[1][j]].first>0 && atom_lab[ablocks[2][k]].first>0 ) { + if( mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel() && + mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() && + mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() && + atom_lab[ablocks[0][i]].second!=atom_lab[ablocks[1][j]].second && atom_lab[ablocks[0][i]].second!=atom_lab[ablocks[2][k]].second && + atom_lab[ablocks[1][j]].second!=atom_lab[ablocks[2][k]].second ) addTaskToList( nblock*nblock*i + nblock*j + k ); + } else if( all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[1][j]].second] && + all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] && + all_atoms[atom_lab[ablocks[1][j]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] ) addTaskToList( nblock*nblock*i + nblock*j + k ); } + bookeeping(i,j).second=getFullNumberOfTasks(); } + } } else { - ablocks[2].resize( atom_lab.size() - ablocks[1].size() - ablocks[0].size() ); - for(unsigned i=0;i<ablocks[2].size();++i) ablocks[2][i] = ablocks[0].size() + ablocks[1].size() + i; - - if( ablocks[1].size()>ablocks[0].size() ) nblock=ablocks[1].size(); - else nblock=ablocks[0].size(); - if( ablocks[2].size()>nblock ) nblock=ablocks[2].size(); - - unsigned kcount; if( no_third_dim_accum ) kcount=1; else kcount=ablocks[2].size(); - - for(unsigned i=0;i<ablocks[0].size();++i){ - for(unsigned j=0;j<ablocks[1].size();++j){ - bookeeping(i,j).first=getFullNumberOfTasks(); - for(unsigned k=0;k<kcount;++k){ - if( no_third_dim_accum ) addTaskToList( nblock*i + j ); - else if( atom_lab[ablocks[0][i]].first>0 && atom_lab[ablocks[1][j]].first>0 && atom_lab[ablocks[2][k]].first>0 ){ - if( mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel() && - mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() && - mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() && - atom_lab[ablocks[0][i]].second!=atom_lab[ablocks[1][j]].second && atom_lab[ablocks[0][i]].second!=atom_lab[ablocks[2][k]].second && - atom_lab[ablocks[1][j]].second!=atom_lab[ablocks[2][k]].second ) addTaskToList( nblock*nblock*i + nblock*j + k ); - } else if( all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[1][j]].second] && - all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] && - all_atoms[atom_lab[ablocks[1][j]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] ) addTaskToList( nblock*nblock*i + nblock*j + k ); - } - bookeeping(i,j).second=getFullNumberOfTasks(); - } + ablocks[2].resize( atom_lab.size() - ablocks[1].size() - ablocks[0].size() ); + for(unsigned i=0; i<ablocks[2].size(); ++i) ablocks[2][i] = ablocks[0].size() + ablocks[1].size() + i; + + if( ablocks[1].size()>ablocks[0].size() ) nblock=ablocks[1].size(); + else nblock=ablocks[0].size(); + if( ablocks[2].size()>nblock ) nblock=ablocks[2].size(); + + unsigned kcount; if( no_third_dim_accum ) kcount=1; else kcount=ablocks[2].size(); + + for(unsigned i=0; i<ablocks[0].size(); ++i) { + for(unsigned j=0; j<ablocks[1].size(); ++j) { + bookeeping(i,j).first=getFullNumberOfTasks(); + for(unsigned k=0; k<kcount; ++k) { + if( no_third_dim_accum ) addTaskToList( nblock*i + j ); + else if( atom_lab[ablocks[0][i]].first>0 && atom_lab[ablocks[1][j]].first>0 && atom_lab[ablocks[2][k]].first>0 ) { + if( mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel() && + mybasemulticolvars[atom_lab[ablocks[0][i]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() && + mybasemulticolvars[atom_lab[ablocks[1][j]].first-1]->getLabel()!=mybasemulticolvars[atom_lab[ablocks[2][k]].first-1]->getLabel() && + atom_lab[ablocks[0][i]].second!=atom_lab[ablocks[1][j]].second && atom_lab[ablocks[0][i]].second!=atom_lab[ablocks[2][k]].second && + atom_lab[ablocks[1][j]].second!=atom_lab[ablocks[2][k]].second ) addTaskToList( nblock*nblock*i + nblock*j + k ); + } else if( all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[1][j]].second] && + all_atoms[atom_lab[ablocks[0][i]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] && + all_atoms[atom_lab[ablocks[1][j]].second]!=all_atoms[atom_lab[ablocks[2][k]].second] ) addTaskToList( nblock*nblock*i + nblock*j + k ); + } + bookeeping(i,j).second=getFullNumberOfTasks(); } + } } } -void MultiColvarBase::buildSets(){ +void MultiColvarBase::buildSets() { std::vector<AtomNumber> fake_atoms; if( !parseMultiColvarAtomList("DATA",-1,fake_atoms) ) error("missing DATA keyword"); if( fake_atoms.size()>0 ) error("no atoms should appear in the specification for this object. Input should be other multicolvars"); nblock = mybasemulticolvars[0]->getFullNumberOfTasks(); - for(unsigned i=0;i<mybasemulticolvars.size();++i){ - if( mybasemulticolvars[i]->getFullNumberOfTasks()!=nblock ){ - error("mismatch between numbers of tasks in various base multicolvars"); - } + for(unsigned i=0; i<mybasemulticolvars.size(); ++i) { + if( mybasemulticolvars[i]->getFullNumberOfTasks()!=nblock ) { + error("mismatch between numbers of tasks in various base multicolvars"); + } } ablocks.resize( mybasemulticolvars.size() ); usespecies=false; - for(unsigned i=0;i<mybasemulticolvars.size();++i){ - ablocks[i].resize( nblock ); - for(unsigned j=0;j<nblock;++j) ablocks[i][j]=i*nblock+j; + for(unsigned i=0; i<mybasemulticolvars.size(); ++i) { + ablocks[i].resize( nblock ); + for(unsigned j=0; j<nblock; ++j) ablocks[i][j]=i*nblock+j; } - for(unsigned i=0;i<nblock;++i){ - if( mybasemulticolvars.size()<4 ){ - unsigned cvcode=0, tmpc=1; - for(unsigned j=0;j<ablocks.size();++j){ cvcode += i*tmpc; tmpc *= nblock; } - addTaskToList( cvcode ); - } else { - addTaskToList( i ); - } + for(unsigned i=0; i<nblock; ++i) { + if( mybasemulticolvars.size()<4 ) { + unsigned cvcode=0, tmpc=1; + for(unsigned j=0; j<ablocks.size(); ++j) { cvcode += i*tmpc; tmpc *= nblock; } + addTaskToList( cvcode ); + } else { + addTaskToList( i ); + } } mybasedata[0]->resizeTemporyMultiValues( mybasemulticolvars.size() ); setupMultiColvarBase( fake_atoms ); } -void MultiColvarBase::addTaskToList( const unsigned& taskCode ){ +void MultiColvarBase::addTaskToList( const unsigned& taskCode ) { plumed_assert( getNumberOfVessels()==0 ); ActionWithVessel::addTaskToList( taskCode ); } -void MultiColvarBase::resizeBookeepingArray( const unsigned& num1, const unsigned& num2 ){ +void MultiColvarBase::resizeBookeepingArray( const unsigned& num1, const unsigned& num2 ) { bookeeping.resize( num1, num2 ); - for(unsigned i=0;i<num1;++i){ - for(unsigned j=0;j<num2;++j){ bookeeping(i,j).first=0; bookeeping(i,j).second=0; } + for(unsigned i=0; i<num1; ++i) { + for(unsigned j=0; j<num2; ++j) { bookeeping(i,j).first=0; bookeeping(i,j).second=0; } } } -void MultiColvarBase::setupMultiColvarBase( const std::vector<AtomNumber>& atoms ){ +void MultiColvarBase::setupMultiColvarBase( const std::vector<AtomNumber>& atoms ) { if( !matsums && atom_lab.size()==0 ) error("No atoms have been read in"); std::vector<AtomNumber> all_atoms; // Setup decoder array - if( !usespecies && nblock>0 ){ - - ncentral=ablocks.size(); use_for_central_atom.resize( ablocks.size(), true ); - numberForCentralAtom = 1.0 / static_cast<double>( ablocks.size() ); - if( ablocks.size()==3 ){ - allthirdblockintasks=uselinkforthree=true; - for(unsigned i=0;i<bookeeping.nrows();++i){ - for(unsigned j=0;j<bookeeping.ncols();++j){ - unsigned ntper = bookeeping(i,j).second - bookeeping(i,j).first; - if( i==j && ntper==0 ){ - continue; - } else if( ntper == 1 && allthirdblockintasks ){ - allthirdblockintasks=true; - } else if( ntper != ablocks[2].size() ){ - allthirdblockintasks=uselinkforthree=false; - } else { - allthirdblockintasks=false; - } - } - } - } - - if( allthirdblockintasks ){ - decoder.resize(2); plumed_assert( ablocks.size()==3 ); - // Check if number of atoms is too large - if( pow( double(nblock), 2.0 )>std::numeric_limits<unsigned>::max() ) error("number of atoms in groups is too big for PLUMED to handle"); - } else { - decoder.resize( ablocks.size() ); - // Check if number of atoms is too large - if( pow( double(nblock), double(ablocks.size()) )>std::numeric_limits<unsigned>::max() ) error("number of atoms in groups is too big for PLUMED to handle"); - } - unsigned code=1; for(unsigned i=0;i<decoder.size();++i){ decoder[decoder.size()-1-i]=code; code *= nblock; } - } else if( !usespecies ){ - ncentral=ablocks.size(); use_for_central_atom.resize( ablocks.size(), true ); - numberForCentralAtom = 1.0 / static_cast<double>( ablocks.size() ); - } else if( keywords.exists("SPECIESA") ){ - plumed_assert( atom_lab.size()==0 && all_atoms.size()==0 ); - ablocks.resize( 1 ); bool readspecies=parseMultiColvarAtomList("SPECIES", -1, all_atoms); - if( readspecies ){ - ablocks[0].resize( atom_lab.size() ); for(unsigned i=0;i<atom_lab.size();++i){ addTaskToList(i); ablocks[0][i]=i; } - } else { - if( !parseMultiColvarAtomList("SPECIESA", -1, all_atoms) ) error("missing SPECIES/SPECIESA keyword"); - unsigned nat1=atom_lab.size(); - if( !parseMultiColvarAtomList("SPECIESB", -1, all_atoms) ) error("missing SPECIESB keyword"); - unsigned nat2=atom_lab.size() - nat1; - - for(unsigned i=0;i<nat1;++i) addTaskToList(i); - ablocks[0].resize( nat2 ); - for(unsigned i=0;i<nat2;++i){ - bool found=false; unsigned inum; - for(unsigned j=0;j<nat1;++j){ - if( atom_lab[nat1+i].first>0 && atom_lab[j].first>0 ){ - if( mybasemulticolvars[atom_lab[nat1+i].first-1]->getAbsoluteIndexOfCentralAtom(atom_lab[nat1+i].second)== - mybasemulticolvars[atom_lab[j].first-1]->getAbsoluteIndexOfCentralAtom(atom_lab[j].second) ){ found=true; inum=j; break; } - } else if( all_atoms[atom_lab[nat1+i].second]==all_atoms[atom_lab[j].second] ){ found=true; inum=j; break; } - } - // This prevents mistakes being made in colvar setup - if( found ){ ablocks[0][i]=inum; } - else { ablocks[0][i]=nat1 + i; } - } - } - } - if( mybasemulticolvars.size()>0 ){ - for(unsigned i=0;i<mybasedata.size();++i){ - mybasedata[i]->resizeTemporyMultiValues(2); mybasemulticolvars[i]->my_tmp_capacks.resize(2); + if( !usespecies && nblock>0 ) { + + ncentral=ablocks.size(); use_for_central_atom.resize( ablocks.size(), true ); + numberForCentralAtom = 1.0 / static_cast<double>( ablocks.size() ); + if( ablocks.size()==3 ) { + allthirdblockintasks=uselinkforthree=true; + for(unsigned i=0; i<bookeeping.nrows(); ++i) { + for(unsigned j=0; j<bookeeping.ncols(); ++j) { + unsigned ntper = bookeeping(i,j).second - bookeeping(i,j).first; + if( i==j && ntper==0 ) { + continue; + } else if( ntper == 1 && allthirdblockintasks ) { + allthirdblockintasks=true; + } else if( ntper != ablocks[2].size() ) { + allthirdblockintasks=uselinkforthree=false; + } else { + allthirdblockintasks=false; + } + } } + } + + if( allthirdblockintasks ) { + decoder.resize(2); plumed_assert( ablocks.size()==3 ); + // Check if number of atoms is too large + if( pow( double(nblock), 2.0 )>std::numeric_limits<unsigned>::max() ) error("number of atoms in groups is too big for PLUMED to handle"); + } else { + decoder.resize( ablocks.size() ); + // Check if number of atoms is too large + if( pow( double(nblock), double(ablocks.size()) )>std::numeric_limits<unsigned>::max() ) error("number of atoms in groups is too big for PLUMED to handle"); + } + unsigned code=1; for(unsigned i=0; i<decoder.size(); ++i) { decoder[decoder.size()-1-i]=code; code *= nblock; } + } else if( !usespecies ) { + ncentral=ablocks.size(); use_for_central_atom.resize( ablocks.size(), true ); + numberForCentralAtom = 1.0 / static_cast<double>( ablocks.size() ); + } else if( keywords.exists("SPECIESA") ) { + plumed_assert( atom_lab.size()==0 && all_atoms.size()==0 ); + ablocks.resize( 1 ); bool readspecies=parseMultiColvarAtomList("SPECIES", -1, all_atoms); + if( readspecies ) { + ablocks[0].resize( atom_lab.size() ); for(unsigned i=0; i<atom_lab.size(); ++i) { addTaskToList(i); ablocks[0][i]=i; } + } else { + if( !parseMultiColvarAtomList("SPECIESA", -1, all_atoms) ) error("missing SPECIES/SPECIESA keyword"); + unsigned nat1=atom_lab.size(); + if( !parseMultiColvarAtomList("SPECIESB", -1, all_atoms) ) error("missing SPECIESB keyword"); + unsigned nat2=atom_lab.size() - nat1; + + for(unsigned i=0; i<nat1; ++i) addTaskToList(i); + ablocks[0].resize( nat2 ); + for(unsigned i=0; i<nat2; ++i) { + bool found=false; unsigned inum; + for(unsigned j=0; j<nat1; ++j) { + if( atom_lab[nat1+i].first>0 && atom_lab[j].first>0 ) { + if( mybasemulticolvars[atom_lab[nat1+i].first-1]->getAbsoluteIndexOfCentralAtom(atom_lab[nat1+i].second)== + mybasemulticolvars[atom_lab[j].first-1]->getAbsoluteIndexOfCentralAtom(atom_lab[j].second) ) { found=true; inum=j; break; } + } else if( all_atoms[atom_lab[nat1+i].second]==all_atoms[atom_lab[j].second] ) { found=true; inum=j; break; } + } + // This prevents mistakes being made in colvar setup + if( found ) { ablocks[0][i]=inum; } + else { ablocks[0][i]=nat1 + i; } + } + } + } + if( mybasemulticolvars.size()>0 ) { + for(unsigned i=0; i<mybasedata.size(); ++i) { + mybasedata[i]->resizeTemporyMultiValues(2); mybasemulticolvars[i]->my_tmp_capacks.resize(2); + } } - // Copy lists of atoms involved from base multicolvars + // Copy lists of atoms involved from base multicolvars std::vector<AtomNumber> tmp_atoms; - for(unsigned i=0;i<mybasemulticolvars.size();++i){ - tmp_atoms=mybasemulticolvars[i]->getAbsoluteIndexes(); - for(unsigned j=0;j<tmp_atoms.size();++j) all_atoms.push_back( tmp_atoms[j] ); - } + for(unsigned i=0; i<mybasemulticolvars.size(); ++i) { + tmp_atoms=mybasemulticolvars[i]->getAbsoluteIndexes(); + for(unsigned j=0; j<tmp_atoms.size(); ++j) all_atoms.push_back( tmp_atoms[j] ); + } // Copy atom lists from input - if( !usespecies ){ - for(unsigned i=0;i<atoms.size();++i) all_atoms.push_back( atoms[i] ); + if( !usespecies ) { + for(unsigned i=0; i<atoms.size(); ++i) all_atoms.push_back( atoms[i] ); } - // Now make sure we get all the atom positions + // Now make sure we get all the atom positions ActionAtomistic::requestAtoms( all_atoms ); // And setup dependencies - for(unsigned i=0;i<mybasemulticolvars.size();++i) addDependency( mybasemulticolvars[i] ); + for(unsigned i=0; i<mybasemulticolvars.size(); ++i) addDependency( mybasemulticolvars[i] ); // Setup underlying ActionWithVessel readVesselKeywords(); } -void MultiColvarBase::setAtomsForCentralAtom( const std::vector<bool>& catom_ind ){ +void MultiColvarBase::setAtomsForCentralAtom( const std::vector<bool>& catom_ind ) { unsigned nat=0; plumed_assert( catom_ind.size()==ablocks.size() ); - for(unsigned i=0;i<catom_ind.size();++i){ - use_for_central_atom[i]=catom_ind[i]; - if( use_for_central_atom[i] ) nat++; + for(unsigned i=0; i<catom_ind.size(); ++i) { + use_for_central_atom[i]=catom_ind[i]; + if( use_for_central_atom[i] ) nat++; } plumed_dbg_assert( nat>0 ); ncentral=nat; numberForCentralAtom = 1.0 / static_cast<double>( nat ); } -void MultiColvarBase::turnOnDerivatives(){ +void MultiColvarBase::turnOnDerivatives() { ActionWithValue::turnOnDerivatives(); - needsDerivatives(); + needsDerivatives(); forcesToApply.resize( getNumberOfDerivatives() ); -} +} -void MultiColvarBase::setLinkCellCutoff( const double& lcut, double tcut ){ +void MultiColvarBase::setLinkCellCutoff( const double& lcut, double tcut ) { plumed_assert( usespecies || ablocks.size()<4 ); if( tcut<0 ) tcut=lcut; - linkcells.setCutoff( lcut ); + linkcells.setCutoff( lcut ); threecells.setCutoff( tcut ); } @@ -498,131 +498,131 @@ double MultiColvarBase::getLinkCellCutoff() const { return linkcells.getCutoff(); } -void MultiColvarBase::setupLinkCells(){ +void MultiColvarBase::setupLinkCells() { if( (!usespecies && nblock==0) || !linkcells.enabled() ) return ; // Retrieve any atoms that haven't already been retrieved - for(std::vector<MultiColvarBase*>::iterator p=mybasemulticolvars.begin();p!=mybasemulticolvars.end();++p){ - (*p)->retrieveAtoms(); + for(std::vector<MultiColvarBase*>::iterator p=mybasemulticolvars.begin(); p!=mybasemulticolvars.end(); ++p) { + (*p)->retrieveAtoms(); } retrieveAtoms(); unsigned iblock; - if( usespecies ){ - iblock=0; - } else if( ablocks.size()<4 ){ - iblock=1; + if( usespecies ) { + iblock=0; + } else if( ablocks.size()<4 ) { + iblock=1; } else { - plumed_error(); + plumed_error(); } - + // Count number of currently active atoms nactive_atoms=0; - for(unsigned i=0;i<ablocks[iblock].size();++i){ - if( isCurrentlyActive( ablocks[iblock][i] ) ) nactive_atoms++; + for(unsigned i=0; i<ablocks[iblock].size(); ++i) { + if( isCurrentlyActive( ablocks[iblock][i] ) ) nactive_atoms++; } - if( nactive_atoms>0 ){ - std::vector<Vector> ltmp_pos( nactive_atoms ); - std::vector<unsigned> ltmp_ind( nactive_atoms ); - - nactive_atoms=0; - if( usespecies ){ - for(unsigned i=0;i<ablocks[0].size();++i){ - if( !isCurrentlyActive( ablocks[0][i] ) ) continue; - ltmp_ind[nactive_atoms]=ablocks[0][i]; - ltmp_pos[nactive_atoms]=getPositionOfAtomForLinkCells( ltmp_ind[nactive_atoms] ); - nactive_atoms++; - } - } else { - for(unsigned i=0;i<ablocks[1].size();++i){ - if( !isCurrentlyActive( ablocks[1][i] ) ) continue; - ltmp_ind[nactive_atoms]=i; - ltmp_pos[nactive_atoms]=getPositionOfAtomForLinkCells( ablocks[1][i] ); - nactive_atoms++; - } + if( nactive_atoms>0 ) { + std::vector<Vector> ltmp_pos( nactive_atoms ); + std::vector<unsigned> ltmp_ind( nactive_atoms ); + + nactive_atoms=0; + if( usespecies ) { + for(unsigned i=0; i<ablocks[0].size(); ++i) { + if( !isCurrentlyActive( ablocks[0][i] ) ) continue; + ltmp_ind[nactive_atoms]=ablocks[0][i]; + ltmp_pos[nactive_atoms]=getPositionOfAtomForLinkCells( ltmp_ind[nactive_atoms] ); + nactive_atoms++; } + } else { + for(unsigned i=0; i<ablocks[1].size(); ++i) { + if( !isCurrentlyActive( ablocks[1][i] ) ) continue; + ltmp_ind[nactive_atoms]=i; + ltmp_pos[nactive_atoms]=getPositionOfAtomForLinkCells( ablocks[1][i] ); + nactive_atoms++; + } + } - // Build the lists for the link cells - linkcells.buildCellLists( ltmp_pos, ltmp_ind, getPbc() ); + // Build the lists for the link cells + linkcells.buildCellLists( ltmp_pos, ltmp_ind, getPbc() ); } } -void MultiColvarBase::setupNonUseSpeciesLinkCells( const unsigned& my_always_active ){ +void MultiColvarBase::setupNonUseSpeciesLinkCells( const unsigned& my_always_active ) { plumed_assert( !usespecies ); if( nblock==0 || !linkcells.enabled() ) return ; deactivateAllTasks(); - if( !uselinkforthree && nactive_atoms>0 ){ - // Get some parallel info - unsigned stride=comm.Get_size(); - unsigned rank=comm.Get_rank(); - if( serialCalculation() ){ stride=1; rank=0; } - - // Ensure we only do tasks where atoms are in appropriate link cells - std::vector<unsigned> linked_atoms( 1+ablocks[1].size() ); - for(unsigned i=rank;i<ablocks[0].size();i+=stride){ - if( !isCurrentlyActive( ablocks[0][i] ) ) continue; - unsigned natomsper=1; linked_atoms[0]=my_always_active; // Note we always check atom 0 because it is simpler than changing LinkCells.cpp - linkcells.retrieveNeighboringAtoms( getPositionOfAtomForLinkCells( ablocks[0][i] ), natomsper, linked_atoms ); - for(unsigned j=0;j<natomsper;++j){ - for(unsigned k=bookeeping(i,linked_atoms[j]).first;k<bookeeping(i,linked_atoms[j]).second;++k) taskFlags[k]=1; - } - } - } else if( nactive_atoms>0 ){ - // Get some parallel info - unsigned stride=comm.Get_size(); - unsigned rank=comm.Get_rank(); - if( serialCalculation() ){ stride=1; rank=0; } - - unsigned nactive_three=0; - for(unsigned i=0;i<ablocks[2].size();++i){ - if( isCurrentlyActive( ablocks[2][i] ) ) nactive_three++; - } - - std::vector<Vector> lttmp_pos( nactive_three ); - std::vector<unsigned> lttmp_ind( nactive_three ); - - nactive_three=0; - if( allthirdblockintasks ){ - for(unsigned i=0;i<ablocks[2].size();++i){ - if( !isCurrentlyActive( ablocks[2][i] ) ) continue; - lttmp_ind[nactive_three]=ablocks[2][i]; - lttmp_pos[nactive_three]=getPositionOfAtomForLinkCells( ablocks[2][i] ); - nactive_three++; - } - } else { - for(unsigned i=0;i<ablocks[2].size();++i){ - if( !isCurrentlyActive( ablocks[2][i] ) ) continue; - lttmp_ind[nactive_three]=i; - lttmp_pos[nactive_three]=getPositionOfAtomForLinkCells( ablocks[2][i] ); - nactive_three++; - } - } - // Build the list of the link cells - threecells.buildCellLists( lttmp_pos, lttmp_ind, getPbc() ); - - // Ensure we only do tasks where atoms are in appropriate link cells - std::vector<unsigned> linked_atoms( 1+ablocks[1].size() ); - std::vector<unsigned> tlinked_atoms( 1+ablocks[2].size() ); - for(unsigned i=rank;i<ablocks[0].size();i+=stride){ - if( !isCurrentlyActive( ablocks[0][i] ) ) continue; - unsigned natomsper=1; linked_atoms[0]=my_always_active; // Note we always check atom 0 because it is simpler than changing LinkCells.cpp - linkcells.retrieveNeighboringAtoms( getPositionOfAtomForLinkCells( ablocks[0][i] ), natomsper, linked_atoms ); - if( allthirdblockintasks ) { - for(unsigned j=0;j<natomsper;++j){ - for(unsigned k=bookeeping(i,linked_atoms[j]).first;k<bookeeping(i,linked_atoms[j]).second;++k) taskFlags[k]=1; - } - } else { - unsigned ntatomsper=1; tlinked_atoms[0]=lttmp_ind[0]; - threecells.retrieveNeighboringAtoms( getPositionOfAtomForLinkCells( ablocks[0][i] ), ntatomsper, tlinked_atoms ); - for(unsigned j=0;j<natomsper;++j){ - for(unsigned k=0;k<ntatomsper;++k) taskFlags[bookeeping(i,linked_atoms[j]).first+tlinked_atoms[k]]=1; - } - } - } + if( !uselinkforthree && nactive_atoms>0 ) { + // Get some parallel info + unsigned stride=comm.Get_size(); + unsigned rank=comm.Get_rank(); + if( serialCalculation() ) { stride=1; rank=0; } + + // Ensure we only do tasks where atoms are in appropriate link cells + std::vector<unsigned> linked_atoms( 1+ablocks[1].size() ); + for(unsigned i=rank; i<ablocks[0].size(); i+=stride) { + if( !isCurrentlyActive( ablocks[0][i] ) ) continue; + unsigned natomsper=1; linked_atoms[0]=my_always_active; // Note we always check atom 0 because it is simpler than changing LinkCells.cpp + linkcells.retrieveNeighboringAtoms( getPositionOfAtomForLinkCells( ablocks[0][i] ), natomsper, linked_atoms ); + for(unsigned j=0; j<natomsper; ++j) { + for(unsigned k=bookeeping(i,linked_atoms[j]).first; k<bookeeping(i,linked_atoms[j]).second; ++k) taskFlags[k]=1; + } + } + } else if( nactive_atoms>0 ) { + // Get some parallel info + unsigned stride=comm.Get_size(); + unsigned rank=comm.Get_rank(); + if( serialCalculation() ) { stride=1; rank=0; } + + unsigned nactive_three=0; + for(unsigned i=0; i<ablocks[2].size(); ++i) { + if( isCurrentlyActive( ablocks[2][i] ) ) nactive_three++; + } + + std::vector<Vector> lttmp_pos( nactive_three ); + std::vector<unsigned> lttmp_ind( nactive_three ); + + nactive_three=0; + if( allthirdblockintasks ) { + for(unsigned i=0; i<ablocks[2].size(); ++i) { + if( !isCurrentlyActive( ablocks[2][i] ) ) continue; + lttmp_ind[nactive_three]=ablocks[2][i]; + lttmp_pos[nactive_three]=getPositionOfAtomForLinkCells( ablocks[2][i] ); + nactive_three++; + } + } else { + for(unsigned i=0; i<ablocks[2].size(); ++i) { + if( !isCurrentlyActive( ablocks[2][i] ) ) continue; + lttmp_ind[nactive_three]=i; + lttmp_pos[nactive_three]=getPositionOfAtomForLinkCells( ablocks[2][i] ); + nactive_three++; + } + } + // Build the list of the link cells + threecells.buildCellLists( lttmp_pos, lttmp_ind, getPbc() ); + + // Ensure we only do tasks where atoms are in appropriate link cells + std::vector<unsigned> linked_atoms( 1+ablocks[1].size() ); + std::vector<unsigned> tlinked_atoms( 1+ablocks[2].size() ); + for(unsigned i=rank; i<ablocks[0].size(); i+=stride) { + if( !isCurrentlyActive( ablocks[0][i] ) ) continue; + unsigned natomsper=1; linked_atoms[0]=my_always_active; // Note we always check atom 0 because it is simpler than changing LinkCells.cpp + linkcells.retrieveNeighboringAtoms( getPositionOfAtomForLinkCells( ablocks[0][i] ), natomsper, linked_atoms ); + if( allthirdblockintasks ) { + for(unsigned j=0; j<natomsper; ++j) { + for(unsigned k=bookeeping(i,linked_atoms[j]).first; k<bookeeping(i,linked_atoms[j]).second; ++k) taskFlags[k]=1; + } + } else { + unsigned ntatomsper=1; tlinked_atoms[0]=lttmp_ind[0]; + threecells.retrieveNeighboringAtoms( getPositionOfAtomForLinkCells( ablocks[0][i] ), ntatomsper, tlinked_atoms ); + for(unsigned j=0; j<natomsper; ++j) { + for(unsigned k=0; k<ntatomsper; ++k) taskFlags[bookeeping(i,linked_atoms[j]).first+tlinked_atoms[k]]=1; + } + } + } } if( !serialCalculation() ) comm.Sum( taskFlags ); - lockContributors(); + lockContributors(); } void MultiColvarBase::decodeIndexToAtoms( const unsigned& taskCode, std::vector<unsigned>& atoms ) const { @@ -630,118 +630,118 @@ void MultiColvarBase::decodeIndexToAtoms( const unsigned& taskCode, std::vector< if( atoms.size()!=decoder.size() ) atoms.resize( decoder.size() ); unsigned scode = taskCode; - for(unsigned i=0;i<decoder.size();++i){ - unsigned ind=( scode / decoder[i] ); - atoms[i] = ablocks[i][ind]; - scode -= ind*decoder[i]; + for(unsigned i=0; i<decoder.size(); ++i) { + unsigned ind=( scode / decoder[i] ); + atoms[i] = ablocks[i][ind]; + scode -= ind*decoder[i]; } } bool MultiColvarBase::setupCurrentAtomList( const unsigned& taskCode, AtomValuePack& myatoms ) const { - if( isDensity() ){ - myatoms.setNumberOfAtoms( 1 ); myatoms.setAtom( 0, taskCode ); return true; - } else if( usespecies ){ - std::vector<unsigned> task_atoms(1); task_atoms[0]=taskCode; - unsigned natomsper=myatoms.setupAtomsFromLinkCells( task_atoms, getLinkCellPosition(task_atoms), linkcells ); - return natomsper>1; - } else if( matsums ){ - myatoms.setNumberOfAtoms( getNumberOfAtoms() ); - for(unsigned i=0;i<getNumberOfAtoms();++i) myatoms.setAtom( i, i ); - } else if( allthirdblockintasks ){ - plumed_dbg_assert( ablocks.size()==3 ); std::vector<unsigned> atoms(2); decodeIndexToAtoms( taskCode, atoms ); - myatoms.setupAtomsFromLinkCells( atoms, getLinkCellPosition(atoms), threecells ); - } else if( nblock>0 ){ - std::vector<unsigned> atoms( ablocks.size() ); - decodeIndexToAtoms( taskCode, atoms ); myatoms.setNumberOfAtoms( ablocks.size() ); - for(unsigned i=0;i<ablocks.size();++i) myatoms.setAtom( i, atoms[i] ); + if( isDensity() ) { + myatoms.setNumberOfAtoms( 1 ); myatoms.setAtom( 0, taskCode ); return true; + } else if( usespecies ) { + std::vector<unsigned> task_atoms(1); task_atoms[0]=taskCode; + unsigned natomsper=myatoms.setupAtomsFromLinkCells( task_atoms, getLinkCellPosition(task_atoms), linkcells ); + return natomsper>1; + } else if( matsums ) { + myatoms.setNumberOfAtoms( getNumberOfAtoms() ); + for(unsigned i=0; i<getNumberOfAtoms(); ++i) myatoms.setAtom( i, i ); + } else if( allthirdblockintasks ) { + plumed_dbg_assert( ablocks.size()==3 ); std::vector<unsigned> atoms(2); decodeIndexToAtoms( taskCode, atoms ); + myatoms.setupAtomsFromLinkCells( atoms, getLinkCellPosition(atoms), threecells ); + } else if( nblock>0 ) { + std::vector<unsigned> atoms( ablocks.size() ); + decodeIndexToAtoms( taskCode, atoms ); myatoms.setNumberOfAtoms( ablocks.size() ); + for(unsigned i=0; i<ablocks.size(); ++i) myatoms.setAtom( i, atoms[i] ); } else { - myatoms.setNumberOfAtoms( ablocks.size() ); - for(unsigned i=0;i<ablocks.size();++i) myatoms.setAtom( i, ablocks[i][taskCode] ); - } + myatoms.setNumberOfAtoms( ablocks.size() ); + for(unsigned i=0; i<ablocks.size(); ++i) myatoms.setAtom( i, ablocks[i][taskCode] ); + } return true; } -void MultiColvarBase::setupActiveTaskSet( std::vector<unsigned>& active_tasks, const std::string& input_label ){ - if( !setup_completed ){ - bool justVolumes=false; - if( usespecies ){ - justVolumes=true; - for(unsigned i=0;i<getNumberOfVessels();++i){ - vesselbase::StoreDataVessel* mys=dynamic_cast<vesselbase::StoreDataVessel*>( getPntrToVessel(i) ); - if( mys ) continue; - vesselbase::BridgeVessel* myb=dynamic_cast<vesselbase::BridgeVessel*>( getPntrToVessel(i) ); - if( !myb ){ justVolumes=false; break; } - ActionVolume* myv=dynamic_cast<ActionVolume*>( myb->getOutputAction() ); - if( !myv ){ justVolumes=false; break; } - } +void MultiColvarBase::setupActiveTaskSet( std::vector<unsigned>& active_tasks, const std::string& input_label ) { + if( !setup_completed ) { + bool justVolumes=false; + if( usespecies ) { + justVolumes=true; + for(unsigned i=0; i<getNumberOfVessels(); ++i) { + vesselbase::StoreDataVessel* mys=dynamic_cast<vesselbase::StoreDataVessel*>( getPntrToVessel(i) ); + if( mys ) continue; + vesselbase::BridgeVessel* myb=dynamic_cast<vesselbase::BridgeVessel*>( getPntrToVessel(i) ); + if( !myb ) { justVolumes=false; break; } + ActionVolume* myv=dynamic_cast<ActionVolume*>( myb->getOutputAction() ); + if( !myv ) { justVolumes=false; break; } } - deactivateAllTasks(); - if( justVolumes && mydata ){ - if( mydata->getNumberOfDataUsers()==0 ) justVolumes=false; - - for(unsigned i=0;i<mydata->getNumberOfDataUsers();++i){ - MultiColvarBase* myu=dynamic_cast<MultiColvarBase*>( mydata->getDataUser(i) ); - if( myu ){ - myu->setupActiveTaskSet( taskFlags, getLabel() ); - } else { - for(unsigned i=0;i<getFullNumberOfTasks();++i) taskFlags[i]=1; - } - } + } + deactivateAllTasks(); + if( justVolumes && mydata ) { + if( mydata->getNumberOfDataUsers()==0 ) justVolumes=false; + + for(unsigned i=0; i<mydata->getNumberOfDataUsers(); ++i) { + MultiColvarBase* myu=dynamic_cast<MultiColvarBase*>( mydata->getDataUser(i) ); + if( myu ) { + myu->setupActiveTaskSet( taskFlags, getLabel() ); + } else { + for(unsigned i=0; i<getFullNumberOfTasks(); ++i) taskFlags[i]=1; + } } - if( justVolumes ){ - for(unsigned j=0;j<getNumberOfVessels();++j){ - vesselbase::BridgeVessel* myb=dynamic_cast<vesselbase::BridgeVessel*>( getPntrToVessel(j) ); - if( !myb ) continue ; - ActionVolume* myv=dynamic_cast<ActionVolume*>( myb->getOutputAction() ); - if( !myv ) continue ; - myv->retrieveAtoms(); myv->setupRegions(); - - for(unsigned i=0;i<getFullNumberOfTasks();++i){ - if( myv->inVolumeOfInterest(i) ) taskFlags[i]=1; - } - } - } else { - for(unsigned i=0;i<getFullNumberOfTasks();++i) taskFlags[i]=1; - } - - // Now activate all this class - lockContributors(); - // Setup the link cells - setupLinkCells(); - // Ensures that setup is not performed multiple times during one cycle - setup_completed=true; + } + if( justVolumes ) { + for(unsigned j=0; j<getNumberOfVessels(); ++j) { + vesselbase::BridgeVessel* myb=dynamic_cast<vesselbase::BridgeVessel*>( getPntrToVessel(j) ); + if( !myb ) continue ; + ActionVolume* myv=dynamic_cast<ActionVolume*>( myb->getOutputAction() ); + if( !myv ) continue ; + myv->retrieveAtoms(); myv->setupRegions(); + + for(unsigned i=0; i<getFullNumberOfTasks(); ++i) { + if( myv->inVolumeOfInterest(i) ) taskFlags[i]=1; + } + } + } else { + for(unsigned i=0; i<getFullNumberOfTasks(); ++i) taskFlags[i]=1; + } + + // Now activate all this class + lockContributors(); + // Setup the link cells + setupLinkCells(); + // Ensures that setup is not performed multiple times during one cycle + setup_completed=true; } // And activate the tasks in input action - if( getLabel()!=input_label ){ - int input_code=-1; - for(unsigned i=0;i<mybasemulticolvars.size();++i){ - if( mybasemulticolvars[i]->getLabel()==input_label ){ input_code=i+1; break; } - } - - MultiValue my_tvals( getNumberOfQuantities(), getNumberOfDerivatives() ); - AtomValuePack mytmp_atoms( my_tvals, this ); - for(unsigned i=0;i<getFullNumberOfTasks();++i){ - if( !taskIsCurrentlyActive(i) ) continue; - setupCurrentAtomList( getTaskCode(i), mytmp_atoms ); - for(unsigned j=0;j<mytmp_atoms.getNumberOfAtoms();++j){ - unsigned itask=mytmp_atoms.getIndex(j); - if( atom_lab[itask].first==input_code ) active_tasks[ atom_lab[itask].second ]=1; - } + if( getLabel()!=input_label ) { + int input_code=-1; + for(unsigned i=0; i<mybasemulticolvars.size(); ++i) { + if( mybasemulticolvars[i]->getLabel()==input_label ) { input_code=i+1; break; } + } + + MultiValue my_tvals( getNumberOfQuantities(), getNumberOfDerivatives() ); + AtomValuePack mytmp_atoms( my_tvals, this ); + for(unsigned i=0; i<getFullNumberOfTasks(); ++i) { + if( !taskIsCurrentlyActive(i) ) continue; + setupCurrentAtomList( getTaskCode(i), mytmp_atoms ); + for(unsigned j=0; j<mytmp_atoms.getNumberOfAtoms(); ++j) { + unsigned itask=mytmp_atoms.getIndex(j); + if( atom_lab[itask].first==input_code ) active_tasks[ atom_lab[itask].second ]=1; } + } } } -bool MultiColvarBase::filtersUsedAsInput(){ +bool MultiColvarBase::filtersUsedAsInput() { bool inputAreFilters=false; - for(unsigned i=0;i<mybasemulticolvars.size();++i){ - MultiColvarFilter* myfilt=dynamic_cast<MultiColvarFilter*>( mybasemulticolvars[i] ); - if( myfilt || mybasemulticolvars[i]->filtersUsedAsInput() ) inputAreFilters=true; + for(unsigned i=0; i<mybasemulticolvars.size(); ++i) { + MultiColvarFilter* myfilt=dynamic_cast<MultiColvarFilter*>( mybasemulticolvars[i] ); + if( myfilt || mybasemulticolvars[i]->filtersUsedAsInput() ) inputAreFilters=true; } return inputAreFilters; } -void MultiColvarBase::calculate(){ +void MultiColvarBase::calculate() { // Recursive function that sets up tasks setupActiveTaskSet( taskFlags, getLabel() ); @@ -749,38 +749,38 @@ void MultiColvarBase::calculate(){ if( mybasemulticolvars.size()>0 && filtersUsedAsInput() ) setupLinkCells(); // Setup the link cells if we are not using species - if( !usespecies && ablocks.size()>1 ){ - // This loop finds the first active atom, which is always checked because - // of a peculiarity in linkcells - unsigned first_active; - for(unsigned i=0;i<ablocks[0].size();++i){ - if( !isCurrentlyActive( ablocks[1][i] ) ) continue; - else { - first_active=i; break; - } - } - setupNonUseSpeciesLinkCells( first_active ); + if( !usespecies && ablocks.size()>1 ) { + // This loop finds the first active atom, which is always checked because + // of a peculiarity in linkcells + unsigned first_active; + for(unsigned i=0; i<ablocks[0].size(); ++i) { + if( !isCurrentlyActive( ablocks[1][i] ) ) continue; + else { + first_active=i; break; + } + } + setupNonUseSpeciesLinkCells( first_active ); } // And run all tasks runAllTasks(); } -void MultiColvarBase::calculateNumericalDerivatives( ActionWithValue* a ){ +void MultiColvarBase::calculateNumericalDerivatives( ActionWithValue* a ) { if( mybasemulticolvars.size()>0 ) plumed_merror("cannot calculate numerical derivatives for this quantity"); calculateAtomicNumericalDerivatives( this, 0 ); } -void MultiColvarBase::prepare(){ +void MultiColvarBase::prepare() { setup_completed=false; atomsWereRetrieved=false; } -void MultiColvarBase::retrieveAtoms(){ - if( !atomsWereRetrieved ){ ActionAtomistic::retrieveAtoms(); atomsWereRetrieved=true; } +void MultiColvarBase::retrieveAtoms() { + if( !atomsWereRetrieved ) { ActionAtomistic::retrieveAtoms(); atomsWereRetrieved=true; } } void MultiColvarBase::mergeInputDerivatives( const unsigned& ival, const unsigned& start, const unsigned& end, - const unsigned& jatom, const std::vector<double>& der, - MultiValue& myder, AtomValuePack& myatoms ) const { + const unsigned& jatom, const std::vector<double>& der, + MultiValue& myder, AtomValuePack& myatoms ) const { MultiValue& myvals=myatoms.getUnderlyingMultiValue(); plumed_dbg_assert( ival<myatoms.getUnderlyingMultiValue().getNumberOfValues() ); plumed_dbg_assert( start<myder.getNumberOfValues() && end<=myder.getNumberOfValues() ); @@ -790,29 +790,29 @@ void MultiColvarBase::mergeInputDerivatives( const unsigned& ival, const unsigne // Find base colvar unsigned mmc=atom_lab[katom].first - 1; plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) ); // Get start of indices for this atom - unsigned basen=0; for(unsigned i=0;i<mmc;++i) basen+=mybasemulticolvars[i]->getNumberOfDerivatives() - 9; + unsigned basen=0; for(unsigned i=0; i<mmc; ++i) basen+=mybasemulticolvars[i]->getNumberOfDerivatives() - 9; plumed_dbg_assert( basen%3==0 ); // Check the number of atoms is consistent with input derivatives unsigned virbas = myvals.getNumberOfDerivatives()-9; - for(unsigned j=0;j<myder.getNumberActive();++j){ - unsigned jder=myder.getActiveIndex(j); - if( jder<mybasemulticolvars[mmc]->getNumberOfDerivatives()-9 ){ - unsigned kder=basen+jder; - for(unsigned icomp=start;icomp<end;++icomp){ - myvals.addDerivative( ival, kder, der[icomp]*myder.getDerivative( icomp, jder ) ); - } - } else { - unsigned kder=virbas + (jder - mybasemulticolvars[mmc]->getNumberOfDerivatives() + 9); - for(unsigned icomp=start;icomp<end;++icomp){ - myvals.addDerivative( ival, kder, der[icomp]*myder.getDerivative( icomp, jder ) ); - } - } + for(unsigned j=0; j<myder.getNumberActive(); ++j) { + unsigned jder=myder.getActiveIndex(j); + if( jder<mybasemulticolvars[mmc]->getNumberOfDerivatives()-9 ) { + unsigned kder=basen+jder; + for(unsigned icomp=start; icomp<end; ++icomp) { + myvals.addDerivative( ival, kder, der[icomp]*myder.getDerivative( icomp, jder ) ); + } + } else { + unsigned kder=virbas + (jder - mybasemulticolvars[mmc]->getNumberOfDerivatives() + 9); + for(unsigned icomp=start; icomp<end; ++icomp) { + myvals.addDerivative( ival, kder, der[icomp]*myder.getDerivative( icomp, jder ) ); + } + } } } void MultiColvarBase::splitInputDerivatives( const unsigned& ival, const unsigned& start, const unsigned& end, - const unsigned& jatom, const std::vector<double>& der, - MultiValue& myder, AtomValuePack& myatoms ) const { + const unsigned& jatom, const std::vector<double>& der, + MultiValue& myder, AtomValuePack& myatoms ) const { MultiValue& myvals=myatoms.getUnderlyingMultiValue(); plumed_dbg_assert( ival<myder.getNumberOfValues() ); plumed_dbg_assert( start<myvals.getNumberOfValues() && end<=myvals.getNumberOfValues() ); @@ -822,24 +822,24 @@ void MultiColvarBase::splitInputDerivatives( const unsigned& ival, const unsigne // Find base colvar unsigned mmc=atom_lab[katom].first - 1; plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) ); // Get start of indices for this atom - unsigned basen=0; for(unsigned i=0;i<mmc;++i) basen+=mybasemulticolvars[i]->getNumberOfDerivatives() - 9; + unsigned basen=0; for(unsigned i=0; i<mmc; ++i) basen+=mybasemulticolvars[i]->getNumberOfDerivatives() - 9; plumed_dbg_assert( basen%3==0 ); // Check the number of atoms is consistent with input derivatives unsigned virbas = myvals.getNumberOfDerivatives()-9; - for(unsigned j=0;j<myder.getNumberActive();++j){ - unsigned jder=myder.getActiveIndex(j); - if( jder<mybasemulticolvars[mmc]->getNumberOfDerivatives()-9 ){ - unsigned kder=basen+jder; plumed_assert( kder<myvals.getNumberOfDerivatives() ); - for(unsigned icomp=start;icomp<end;++icomp){ - myvals.addDerivative( icomp, kder, der[icomp]*myder.getDerivative( ival, jder ) ); - } - } else { - unsigned kder=virbas + (jder - mybasemulticolvars[mmc]->getNumberOfDerivatives() + 9); - for(unsigned icomp=start;icomp<end;++icomp){ - myvals.addDerivative( icomp, kder, der[icomp]*myder.getDerivative( ival, jder ) ); - } - } + for(unsigned j=0; j<myder.getNumberActive(); ++j) { + unsigned jder=myder.getActiveIndex(j); + if( jder<mybasemulticolvars[mmc]->getNumberOfDerivatives()-9 ) { + unsigned kder=basen+jder; plumed_assert( kder<myvals.getNumberOfDerivatives() ); + for(unsigned icomp=start; icomp<end; ++icomp) { + myvals.addDerivative( icomp, kder, der[icomp]*myder.getDerivative( ival, jder ) ); + } + } else { + unsigned kder=virbas + (jder - mybasemulticolvars[mmc]->getNumberOfDerivatives() + 9); + for(unsigned icomp=start; icomp<end; ++icomp) { + myvals.addDerivative( icomp, kder, der[icomp]*myder.getDerivative( ival, jder ) ); + } + } } -} +} void MultiColvarBase::addComDerivatives( const int& ival, const unsigned& iatom, const Vector& der, multicolvar::AtomValuePack& myatoms ) const { plumed_dbg_assert( ival<static_cast<int>(myatoms.getUnderlyingMultiValue().getNumberOfValues()) && iatom<myatoms.getNumberOfAtoms() ); @@ -847,40 +847,40 @@ void MultiColvarBase::addComDerivatives( const int& ival, const unsigned& iatom, unsigned katom = myatoms.getIndex( iatom ); plumed_dbg_assert( atom_lab[katom].first>0 ); // Find base colvar unsigned mmc = atom_lab[katom].first - 1; plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) ); - if( usespecies && iatom==0 ){ myatoms.addComDerivatives( ival, der, mybasemulticolvars[mmc]->my_tmp_capacks[0] ); return; } + if( usespecies && iatom==0 ) { myatoms.addComDerivatives( ival, der, mybasemulticolvars[mmc]->my_tmp_capacks[0] ); return; } // Get start of indices for this atom - unsigned basen=0; for(unsigned i=0;i<mmc;++i) basen+=(mybasemulticolvars[i]->getNumberOfDerivatives() - 9) / 3; + unsigned basen=0; for(unsigned i=0; i<mmc; ++i) basen+=(mybasemulticolvars[i]->getNumberOfDerivatives() - 9) / 3; mybasemulticolvars[mmc]->getCentralAtomPack( basen, atom_lab[katom].second, mybasemulticolvars[mmc]->my_tmp_capacks[1] ); myatoms.addComDerivatives( ival, der, mybasemulticolvars[mmc]->my_tmp_capacks[1] ); } -void MultiColvarBase::getInputData( const unsigned& ind, const bool& normed, - const multicolvar::AtomValuePack& myatoms, +void MultiColvarBase::getInputData( const unsigned& ind, const bool& normed, + const multicolvar::AtomValuePack& myatoms, std::vector<double>& orient ) const { // Converint input atom to local index - unsigned katom = myatoms.getIndex(ind); plumed_dbg_assert( atom_lab[katom].first>0 ); + unsigned katom = myatoms.getIndex(ind); plumed_dbg_assert( atom_lab[katom].first>0 ); // Find base colvar unsigned mmc = atom_lab[katom].first - 1; plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) ); // Check if orient is the correct size - if( orient.size()!=mybasemulticolvars[mmc]->getNumberOfQuantities() ) orient.resize( mybasemulticolvars[mmc]->getNumberOfQuantities() ); - // Retrieve the value + if( orient.size()!=mybasemulticolvars[mmc]->getNumberOfQuantities() ) orient.resize( mybasemulticolvars[mmc]->getNumberOfQuantities() ); + // Retrieve the value mybasedata[mmc]->retrieveValueWithIndex( atom_lab[katom].second, normed, orient ); } MultiValue& MultiColvarBase::getInputDerivatives( const unsigned& iatom, const bool& normed, const multicolvar::AtomValuePack& myatoms ) const { // Converint input atom to local index - unsigned katom = myatoms.getIndex(iatom); plumed_dbg_assert( atom_lab[katom].first>0 ); + unsigned katom = myatoms.getIndex(iatom); plumed_dbg_assert( atom_lab[katom].first>0 ); // Find base colvar unsigned mmc = atom_lab[katom].first - 1; plumed_dbg_assert( mybasemulticolvars[mmc]->taskIsCurrentlyActive( atom_lab[katom].second ) ); if( usespecies && !normed && iatom==0 ) return mybasedata[mmc]->getTemporyMultiValue(0); unsigned oval=0; if( iatom>0 ) oval=1; - MultiValue& myder=mybasedata[mmc]->getTemporyMultiValue(oval); + MultiValue& myder=mybasedata[mmc]->getTemporyMultiValue(oval); if( myder.getNumberOfValues()!=mybasemulticolvars[mmc]->getNumberOfQuantities() || - myder.getNumberOfDerivatives()!=mybasemulticolvars[mmc]->getNumberOfDerivatives() ){ - myder.resize( mybasemulticolvars[mmc]->getNumberOfQuantities(), mybasemulticolvars[mmc]->getNumberOfDerivatives() ); - } + myder.getNumberOfDerivatives()!=mybasemulticolvars[mmc]->getNumberOfDerivatives() ) { + myder.resize( mybasemulticolvars[mmc]->getNumberOfQuantities(), mybasemulticolvars[mmc]->getNumberOfDerivatives() ); + } mybasedata[mmc]->retrieveDerivatives( atom_lab[katom].second, normed, myder ); return myder; } @@ -891,31 +891,31 @@ void MultiColvarBase::accumulateSymmetryFunction( const int& ival, const unsigne double weighti=1.0; if( atom_lab[jatom].first>0 ) weighti=mybasedata[atom_lab[jatom].first-1]->retrieveWeightWithIndex( atom_lab[jatom].second ); // Accumulate the value if( ival<0 ) myatoms.getUnderlyingMultiValue().addTemporyValue( weight0*weighti*val ); - else myatoms.addValue( ival, weight0*weighti*val ); + else myatoms.addValue( ival, weight0*weighti*val ); // Return if we don't need derivatives if( doNotCalculateDerivatives() ) return ; // And virial - if( ival<0 ) myatoms.addTemporyBoxDerivatives( weight0*weighti*vir ); + if( ival<0 ) myatoms.addTemporyBoxDerivatives( weight0*weighti*vir ); else myatoms.addBoxDerivatives( ival, weight0*weighti*vir ); // Add derivatives of central atom - if( atom_lab[katom].first>0 ){ - addComDerivatives( ival, 0, -weight0*weighti*der, myatoms ); - std::vector<double> tmpder( mybasemulticolvars[atom_lab[katom].first - 1]->getNumberOfQuantities(), 0. ); - tmpder[0]=weighti*val; mergeInputDerivatives( ival, 0, 1, 0, tmpder, getInputDerivatives(0, false, myatoms), myatoms ); + if( atom_lab[katom].first>0 ) { + addComDerivatives( ival, 0, -weight0*weighti*der, myatoms ); + std::vector<double> tmpder( mybasemulticolvars[atom_lab[katom].first - 1]->getNumberOfQuantities(), 0. ); + tmpder[0]=weighti*val; mergeInputDerivatives( ival, 0, 1, 0, tmpder, getInputDerivatives(0, false, myatoms), myatoms ); } else { - if( ival<0 ) myatoms.addTemporyAtomsDerivatives( 0, -der ); - else myatoms.addAtomsDerivatives( ival, 0, -der ); + if( ival<0 ) myatoms.addTemporyAtomsDerivatives( 0, -der ); + else myatoms.addAtomsDerivatives( ival, 0, -der ); } // Add derivatives of atom in coordination sphere - if( atom_lab[jatom].first>0 ){ - addComDerivatives( ival, iatom, weight0*weighti*der, myatoms ); - std::vector<double> tmpder( mybasemulticolvars[atom_lab[katom].first - 1]->getNumberOfQuantities(), 0. ); - tmpder[0]=weight0*val; mergeInputDerivatives( ival, 0, 1, iatom, tmpder, getInputDerivatives(iatom, false, myatoms), myatoms ); + if( atom_lab[jatom].first>0 ) { + addComDerivatives( ival, iatom, weight0*weighti*der, myatoms ); + std::vector<double> tmpder( mybasemulticolvars[atom_lab[katom].first - 1]->getNumberOfQuantities(), 0. ); + tmpder[0]=weight0*val; mergeInputDerivatives( ival, 0, 1, iatom, tmpder, getInputDerivatives(iatom, false, myatoms), myatoms ); } else { - if( ival<0 ) myatoms.addTemporyAtomsDerivatives( iatom, der ); - else myatoms.addAtomsDerivatives( ival, iatom, der ); + if( ival<0 ) myatoms.addTemporyAtomsDerivatives( iatom, der ); + else myatoms.addAtomsDerivatives( ival, iatom, der ); } } @@ -923,11 +923,11 @@ void MultiColvarBase::addAtomDerivatives( const int& ival, const unsigned& iatom if( doNotCalculateDerivatives() ) return ; unsigned jatom=myatoms.getIndex(iatom); - if( atom_lab[jatom].first>0 ){ - addComDerivatives( ival, iatom, der, myatoms ); + if( atom_lab[jatom].first>0 ) { + addComDerivatives( ival, iatom, der, myatoms ); } else { - if( ival<0 ) myatoms.addTemporyAtomsDerivatives( iatom, der ); - else myatoms.addAtomsDerivatives( ival, iatom, der ); + if( ival<0 ) myatoms.addTemporyAtomsDerivatives( iatom, der ); + else myatoms.addAtomsDerivatives( ival, iatom, der ); } } @@ -940,61 +940,61 @@ void MultiColvarBase::performTask( const unsigned& task_index, const unsigned& c // Retrieve the atom list if( !setupCurrentAtomList( current, myatoms ) ) return; // Get weight due to dynamic groups - double weight = 1.0; - if( !matsums ){ - for(unsigned i=0;i<myatoms.getNumberOfAtoms();++i){ - if( atom_lab[myatoms.getIndex(i)].first==0 ) continue; - // Only need to do first two atoms for thigns like TopologyMatrix, HbondMatrix, Bridge and so on - if( allthirdblockintasks && i>1 ) break; - unsigned mmc = atom_lab[myatoms.getIndex(i)].first - 1; - weight *= mybasedata[mmc]->retrieveWeightWithIndex( atom_lab[myatoms.getIndex(i)].second ); - } - } else if( usespecies ){ - if( atom_lab[myatoms.getIndex(0)].first>0 ){ - if( mybasedata[atom_lab[myatoms.getIndex(0)].first-1]->retrieveWeightWithIndex( atom_lab[myatoms.getIndex(0)].second )<epsilon ) weight=0.; - } - } - // Do a quick check on the size of this contribution - double multweight = calculateWeight( current, weight, myatoms ); - if( weight*multweight<getTolerance() ){ - updateActiveAtoms( myatoms ); - return; + double weight = 1.0; + if( !matsums ) { + for(unsigned i=0; i<myatoms.getNumberOfAtoms(); ++i) { + if( atom_lab[myatoms.getIndex(i)].first==0 ) continue; + // Only need to do first two atoms for thigns like TopologyMatrix, HbondMatrix, Bridge and so on + if( allthirdblockintasks && i>1 ) break; + unsigned mmc = atom_lab[myatoms.getIndex(i)].first - 1; + weight *= mybasedata[mmc]->retrieveWeightWithIndex( atom_lab[myatoms.getIndex(i)].second ); + } + } else if( usespecies ) { + if( atom_lab[myatoms.getIndex(0)].first>0 ) { + if( mybasedata[atom_lab[myatoms.getIndex(0)].first-1]->retrieveWeightWithIndex( atom_lab[myatoms.getIndex(0)].second )<epsilon ) weight=0.; + } } - myatoms.setValue( 0 , weight*multweight ); + // Do a quick check on the size of this contribution + double multweight = calculateWeight( current, weight, myatoms ); + if( weight*multweight<getTolerance() ) { + updateActiveAtoms( myatoms ); + return; + } + myatoms.setValue( 0, weight*multweight ); // Deal with derivatives of weights due to dynamic groups - if( !matsums && !doNotCalculateDerivatives() && mybasemulticolvars.size()>0 ){ - MultiValue& outder=myatoms.getUnderlyingMultiValue(); MultiValue myder(0,0); - for(unsigned i=0;i<myatoms.getNumberOfAtoms();++i){ - // Neglect any atoms without differentiable weights - if( atom_lab[myatoms.getIndex(i)].first==0 ) continue; - - // Retrieve derivatives - unsigned mmc = atom_lab[myatoms.getIndex(i)].first - 1; - if( myder.getNumberOfValues()!=mybasemulticolvars[mmc]->getNumberOfQuantities() || myder.getNumberOfDerivatives()!=mybasemulticolvars[mmc]->getNumberOfDerivatives() ){ - myder.resize( mybasemulticolvars[mmc]->getNumberOfQuantities(), mybasemulticolvars[mmc]->getNumberOfDerivatives() ); - } - mybasedata[mmc]->retrieveDerivatives( atom_lab[myatoms.getIndex(i)].second, false, myder ); - - // Retrieve the prefactor (product of all other weights) - double prefactor = multweight*weight / mybasedata[mmc]->retrieveWeightWithIndex( atom_lab[myatoms.getIndex(i)].second ); - // And accumulate the derivatives - for(unsigned j=0;j<myder.getNumberActive();++j){ unsigned jder=myder.getActiveIndex(j); outder.addDerivative( 0, jder, prefactor*myder.getDerivative(0,jder) ); } - myder.clearAll(); + if( !matsums && !doNotCalculateDerivatives() && mybasemulticolvars.size()>0 ) { + MultiValue& outder=myatoms.getUnderlyingMultiValue(); MultiValue myder(0,0); + for(unsigned i=0; i<myatoms.getNumberOfAtoms(); ++i) { + // Neglect any atoms without differentiable weights + if( atom_lab[myatoms.getIndex(i)].first==0 ) continue; + + // Retrieve derivatives + unsigned mmc = atom_lab[myatoms.getIndex(i)].first - 1; + if( myder.getNumberOfValues()!=mybasemulticolvars[mmc]->getNumberOfQuantities() || myder.getNumberOfDerivatives()!=mybasemulticolvars[mmc]->getNumberOfDerivatives() ) { + myder.resize( mybasemulticolvars[mmc]->getNumberOfQuantities(), mybasemulticolvars[mmc]->getNumberOfDerivatives() ); } + mybasedata[mmc]->retrieveDerivatives( atom_lab[myatoms.getIndex(i)].second, false, myder ); + + // Retrieve the prefactor (product of all other weights) + double prefactor = multweight*weight / mybasedata[mmc]->retrieveWeightWithIndex( atom_lab[myatoms.getIndex(i)].second ); + // And accumulate the derivatives + for(unsigned j=0; j<myder.getNumberActive(); ++j) { unsigned jder=myder.getActiveIndex(j); outder.addDerivative( 0, jder, prefactor*myder.getDerivative(0,jder) ); } + myder.clearAll(); + } } // Retrieve derivative stuff for central atom - if( !doNotCalculateDerivatives() ){ - if( usespecies && mybasemulticolvars.size()>0 && atom_lab[myatoms.getIndex(0)].first>0 ){ - unsigned mmc = atom_lab[0].first - 1; - MultiValue& myder=mybasedata[mmc]->getTemporyMultiValue(0); - if( myder.getNumberOfValues()!=mybasemulticolvars[mmc]->getNumberOfQuantities() || - myder.getNumberOfDerivatives()!=mybasemulticolvars[mmc]->getNumberOfDerivatives() ){ - myder.resize( mybasemulticolvars[mmc]->getNumberOfQuantities(), mybasemulticolvars[mmc]->getNumberOfDerivatives() ); - } - mybasedata[mmc]->retrieveDerivatives( atom_lab[myatoms.getIndex(0)].second, false, myder ); - unsigned basen=0; for(unsigned i=0;i<mmc;++i) basen+=mybasemulticolvars[i]->getNumberOfDerivatives() - 9; - mybasemulticolvars[mmc]->getCentralAtomPack( basen, atom_lab[myatoms.getIndex(0)].second, mybasemulticolvars[mmc]->my_tmp_capacks[0] ); + if( !doNotCalculateDerivatives() ) { + if( usespecies && mybasemulticolvars.size()>0 && atom_lab[myatoms.getIndex(0)].first>0 ) { + unsigned mmc = atom_lab[0].first - 1; + MultiValue& myder=mybasedata[mmc]->getTemporyMultiValue(0); + if( myder.getNumberOfValues()!=mybasemulticolvars[mmc]->getNumberOfQuantities() || + myder.getNumberOfDerivatives()!=mybasemulticolvars[mmc]->getNumberOfDerivatives() ) { + myder.resize( mybasemulticolvars[mmc]->getNumberOfQuantities(), mybasemulticolvars[mmc]->getNumberOfDerivatives() ); } + mybasedata[mmc]->retrieveDerivatives( atom_lab[myatoms.getIndex(0)].second, false, myder ); + unsigned basen=0; for(unsigned i=0; i<mmc; ++i) basen+=mybasemulticolvars[i]->getNumberOfDerivatives() - 9; + mybasemulticolvars[mmc]->getCentralAtomPack( basen, atom_lab[myatoms.getIndex(0)].second, mybasemulticolvars[mmc]->my_tmp_capacks[0] ); + } } // Compute everything double vv=compute( task_index, myatoms ); updateActiveAtoms( myatoms ); @@ -1007,71 +1007,71 @@ void MultiColvarBase::updateActiveAtoms( AtomValuePack& myatoms ) const { else myatoms.updateDynamicList(); } -Vector MultiColvarBase::getCentralAtomPos( const unsigned& taskIndex ){ +Vector MultiColvarBase::getCentralAtomPos( const unsigned& taskIndex ) { unsigned curr=getTaskCode( taskIndex ); - if( usespecies || isDensity() ){ - return getPositionOfAtomForLinkCells(curr); - } else if( nblock>0 ){ - // double factor=1.0/static_cast<double>( ablocks.size() ); - Vector mypos; mypos.zero(); - std::vector<unsigned> atoms( ablocks.size() ); decodeIndexToAtoms( curr, atoms ); - for(unsigned i=0;i<ablocks.size();++i){ - if( use_for_central_atom[i] ) mypos+=numberForCentralAtom*getPositionOfAtomForLinkCells(atoms[i]); - } - return mypos; + if( usespecies || isDensity() ) { + return getPositionOfAtomForLinkCells(curr); + } else if( nblock>0 ) { + // double factor=1.0/static_cast<double>( ablocks.size() ); + Vector mypos; mypos.zero(); + std::vector<unsigned> atoms( ablocks.size() ); decodeIndexToAtoms( curr, atoms ); + for(unsigned i=0; i<ablocks.size(); ++i) { + if( use_for_central_atom[i] ) mypos+=numberForCentralAtom*getPositionOfAtomForLinkCells(atoms[i]); + } + return mypos; } else { - Vector mypos; mypos.zero(); - for(unsigned i=0;i<ablocks.size();++i){ - if( use_for_central_atom[i] ) mypos+=numberForCentralAtom*getPositionOfAtomForLinkCells(ablocks[i][curr]); - } - return mypos; + Vector mypos; mypos.zero(); + for(unsigned i=0; i<ablocks.size(); ++i) { + if( use_for_central_atom[i] ) mypos+=numberForCentralAtom*getPositionOfAtomForLinkCells(ablocks[i][curr]); + } + return mypos; } } -void MultiColvarBase::getCentralAtomPack( const unsigned& basn, const unsigned& taskIndex, CatomPack& mypack ){ +void MultiColvarBase::getCentralAtomPack( const unsigned& basn, const unsigned& taskIndex, CatomPack& mypack ) { unsigned curr=getTaskCode( taskIndex ); - if(usespecies){ - if( mypack.getNumberOfAtomsWithDerivatives()!=1 ) mypack.resize(1); - mypack.setIndex( 0, basn + curr ); - mypack.setDerivative( 0, Tensor::identity() ); - } else if( nblock>0 ){ - if( mypack.getNumberOfAtomsWithDerivatives()!=ncentral ) mypack.resize(ncentral); - unsigned k=0; - std::vector<unsigned> atoms( ablocks.size() ); decodeIndexToAtoms( curr, atoms ); - for(unsigned i=0;i<ablocks.size();++i){ - if( use_for_central_atom[i] ){ - mypack.setIndex( k, basn + atoms[i] ); - mypack.setDerivative( k, numberForCentralAtom*Tensor::identity() ); - k++; - } - } + if(usespecies) { + if( mypack.getNumberOfAtomsWithDerivatives()!=1 ) mypack.resize(1); + mypack.setIndex( 0, basn + curr ); + mypack.setDerivative( 0, Tensor::identity() ); + } else if( nblock>0 ) { + if( mypack.getNumberOfAtomsWithDerivatives()!=ncentral ) mypack.resize(ncentral); + unsigned k=0; + std::vector<unsigned> atoms( ablocks.size() ); decodeIndexToAtoms( curr, atoms ); + for(unsigned i=0; i<ablocks.size(); ++i) { + if( use_for_central_atom[i] ) { + mypack.setIndex( k, basn + atoms[i] ); + mypack.setDerivative( k, numberForCentralAtom*Tensor::identity() ); + k++; + } + } } else { - if( mypack.getNumberOfAtomsWithDerivatives()!=ncentral ) mypack.resize(ncentral); - unsigned k=0; - for(unsigned i=0;i<ablocks.size();++i){ - if( use_for_central_atom[i] ){ - mypack.setIndex( k, basn + ablocks[i][curr] ); - mypack.setDerivative( k, numberForCentralAtom*Tensor::identity() ); - k++; - } - } + if( mypack.getNumberOfAtomsWithDerivatives()!=ncentral ) mypack.resize(ncentral); + unsigned k=0; + for(unsigned i=0; i<ablocks.size(); ++i) { + if( use_for_central_atom[i] ) { + mypack.setIndex( k, basn + ablocks[i][curr] ); + mypack.setDerivative( k, numberForCentralAtom*Tensor::identity() ); + k++; + } + } } -} +} Vector MultiColvarBase::getSeparation( const Vector& vec1, const Vector& vec2 ) const { - if(usepbc){ return pbcDistance( vec1, vec2 ); } - else{ return delta( vec1, vec2 ); } + if(usepbc) { return pbcDistance( vec1, vec2 ); } + else { return delta( vec1, vec2 ); } } void MultiColvarBase::applyPbc(std::vector<Vector>& dlist, unsigned int max_index) const { - if (usepbc) pbcApply(dlist, max_index); + if (usepbc) pbcApply(dlist, max_index); } -void MultiColvarBase::apply(){ +void MultiColvarBase::apply() { if( getForcesFromVessels( forcesToApply ) ) setForcesOnAtoms( forcesToApply ); } - + } } diff --git a/src/multicolvar/MultiColvarBase.h b/src/multicolvar/MultiColvarBase.h index 8d94a9322..89574a70a 100644 --- a/src/multicolvar/MultiColvarBase.h +++ b/src/multicolvar/MultiColvarBase.h @@ -42,11 +42,11 @@ class MultiColvarBase : public ActionAtomistic, public ActionWithValue, public vesselbase::ActionWithVessel - { - friend class BridgedMultiColvarFunction; - friend class VolumeGradientBase; - friend class MultiColvarFilter; - friend class AtomValuePack; +{ + friend class BridgedMultiColvarFunction; + friend class VolumeGradientBase; + friend class MultiColvarFilter; + friend class AtomValuePack; private: /// Use periodic boundary conditions bool usepbc; @@ -105,9 +105,9 @@ protected: /// Finish setting up the multicolvar base void setupMultiColvarBase( const std::vector<AtomNumber>& atoms ); /// Add some derivatives to a particular component of a particular atom - void addAtomDerivatives( const int& , const unsigned& , const Vector& , multicolvar::AtomValuePack& ) const ; + void addAtomDerivatives( const int&, const unsigned&, const Vector&, multicolvar::AtomValuePack& ) const ; /// Add derivative of the input value - void mergeInputDerivatives( const unsigned& ival, const unsigned& start, const unsigned& end, const unsigned& jatom, + void mergeInputDerivatives( const unsigned& ival, const unsigned& start, const unsigned& end, const unsigned& jatom, const std::vector<double>& der, MultiValue& myder, AtomValuePack& myatoms ) const ; /// This routine take the ith set of input derivatives and adds it to each of the (end-start) output derivatives /// In other words one set of derivatives comes in and end-start sets of derivatives come out @@ -150,9 +150,9 @@ protected: void buildSets(); public: explicit MultiColvarBase(const ActionOptions&); - ~MultiColvarBase(){} + ~MultiColvarBase() {} static void registerKeywords( Keywords& keys ); -/// Turn on the derivatives +/// Turn on the derivatives virtual void turnOnDerivatives(); /// Do we use pbc to calculate this quantity bool usesPbc() const ; @@ -169,7 +169,7 @@ public: /// Calculate numerical derivatives virtual void calculateNumericalDerivatives( ActionWithValue* a=NULL ); /// Perform one of the tasks - virtual void performTask( const unsigned& , const unsigned& , MultiValue& ) const ; + virtual void performTask( const unsigned&, const unsigned&, MultiValue& ) const ; /// Update the active atoms virtual void updateActiveAtoms( AtomValuePack& myatoms ) const ; /// This gets the position of an atom for the link cell setup @@ -199,12 +199,12 @@ public: /// This is true if multicolvar is calculating a vector or if the multicolvar is the density virtual bool hasDifferentiableOrientation() const { return false; } /// This makes sure we are not calculating the director when we do LocalAverage - virtual void doNotCalculateDirector(){} + virtual void doNotCalculateDirector() {} /// Ensure that derivatives are only calculated when needed bool doNotCalculateDerivatives() const ; -/// Get the icolv th base multicolvar +/// Get the icolv th base multicolvar MultiColvarBase* getBaseMultiColvar( const unsigned& icolv ) const ; -/// Get the number of base multicolvars +/// Get the number of base multicolvars unsigned getNumberOfBaseMultiColvars() const ; /// Get an input data virtual void getInputData( const unsigned& ind, const bool& normed, const multicolvar::AtomValuePack& myatoms, std::vector<double>& orient ) const ; @@ -213,10 +213,10 @@ public: }; inline -bool MultiColvarBase::isCurrentlyActive( const unsigned& code ){ - if( setup_completed && atom_lab[code].first>0 ){ - unsigned mmc=atom_lab[code].first - 1; - return mybasedata[mmc]->storedValueIsActive( atom_lab[code].second ); +bool MultiColvarBase::isCurrentlyActive( const unsigned& code ) { + if( setup_completed && atom_lab[code].first>0 ) { + unsigned mmc=atom_lab[code].first - 1; + return mybasedata[mmc]->storedValueIsActive( atom_lab[code].second ); } return true; } @@ -224,20 +224,20 @@ bool MultiColvarBase::isCurrentlyActive( const unsigned& code ){ inline AtomNumber MultiColvarBase::getAbsoluteIndexOfCentralAtom( const unsigned& iatom ) const { plumed_dbg_assert( iatom<atom_lab.size() ); - if( atom_lab[iatom].first>0 ){ - unsigned mmc=atom_lab[iatom].first - 1; - return mybasemulticolvars[mmc]->getAbsoluteIndexOfCentralAtom( atom_lab[iatom].second ); + if( atom_lab[iatom].first>0 ) { + unsigned mmc=atom_lab[iatom].first - 1; + return mybasemulticolvars[mmc]->getAbsoluteIndexOfCentralAtom( atom_lab[iatom].second ); } plumed_dbg_assert( usespecies ); return ActionAtomistic::getAbsoluteIndex( atom_lab[getTaskCode(iatom)].second ); -} +} inline Vector MultiColvarBase::getPositionOfAtomForLinkCells( const unsigned& iatom ) const { plumed_dbg_assert( iatom<atom_lab.size() ); - if( atom_lab[iatom].first>0 ){ - unsigned mmc=atom_lab[iatom].first - 1; - return mybasemulticolvars[mmc]->getCentralAtomPos( atom_lab[iatom].second ); + if( atom_lab[iatom].first>0 ) { + unsigned mmc=atom_lab[iatom].first - 1; + return mybasemulticolvars[mmc]->getCentralAtomPos( atom_lab[iatom].second ); } return ActionAtomistic::getPosition( atom_lab[iatom].second ); } @@ -245,10 +245,10 @@ Vector MultiColvarBase::getPositionOfAtomForLinkCells( const unsigned& iatom ) c inline Vector MultiColvarBase::getLinkCellPosition( const std::vector<unsigned>& atoms ) const { return getPositionOfAtomForLinkCells( atoms[0] ); -} +} inline -unsigned MultiColvarBase::getNumberOfDerivatives(){ +unsigned MultiColvarBase::getNumberOfDerivatives() { return 3*getNumberOfAtoms()+9; } @@ -265,14 +265,14 @@ bool MultiColvarBase::doNotCalculateDerivatives() const { inline unsigned MultiColvarBase::getNumberOfBaseMultiColvars() const { - return mybasemulticolvars.size(); -} + return mybasemulticolvars.size(); +} -inline +inline MultiColvarBase* MultiColvarBase::getBaseMultiColvar( const unsigned& icolv ) const { plumed_dbg_assert( icolv<mybasemulticolvars.size() ); - return mybasemulticolvars[icolv]; -} + return mybasemulticolvars[icolv]; +} } } diff --git a/src/multicolvar/MultiColvarCombine.cpp b/src/multicolvar/MultiColvarCombine.cpp index 0aa0d26d0..24bd9e6e4 100644 --- a/src/multicolvar/MultiColvarCombine.cpp +++ b/src/multicolvar/MultiColvarCombine.cpp @@ -24,7 +24,7 @@ #include "core/ActionRegister.h" #include <string> -#include <cmath> +#include <cmath> //+PLUMEDOC MCOLVARF MCOLV_COMBINE /* @@ -47,46 +47,46 @@ public: /// Actually do the calculation double compute( const unsigned& tindex, AtomValuePack& myatoms ) const ; /// Is the variable periodic - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } }; PLUMED_REGISTER_ACTION(MultiColvarCombine,"MCOLV_COMBINE") -void MultiColvarCombine::registerKeywords( Keywords& keys ){ +void MultiColvarCombine::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); keys.add("compulsory","DATA","the multicolvars you are calculating linear combinations for"); keys.add("compulsory","COEFFICIENTS","1.0","the coeficients to use for the various multicolvars"); - keys.use("MEAN"); keys.use("MORE_THAN"); keys.use("SUM"); keys.use("LESS_THAN"); keys.use("HISTOGRAM"); keys.use("HISTOGRAM"); + keys.use("MEAN"); keys.use("MORE_THAN"); keys.use("SUM"); keys.use("LESS_THAN"); keys.use("HISTOGRAM"); keys.use("HISTOGRAM"); keys.use("MIN"); keys.use("MAX"); keys.use("LOWEST"); keys.use("HIGHEST"); keys.use("ALT_MIN"); keys.use("BETWEEN"); keys.use("MOMENTS"); } MultiColvarCombine::MultiColvarCombine(const ActionOptions& ao): -Action(ao), -MultiColvarBase(ao) + Action(ao), + MultiColvarBase(ao) { buildSets(); - for(unsigned i=0;i<getNumberOfBaseMultiColvars();++i){ - if( mybasemulticolvars[i]->weightWithDerivatives() ) error("cannot combine multicolvars with weights"); + for(unsigned i=0; i<getNumberOfBaseMultiColvars(); ++i) { + if( mybasemulticolvars[i]->weightWithDerivatives() ) error("cannot combine multicolvars with weights"); } coeff.resize( getNumberOfBaseMultiColvars() ); parseVector("COEFFICIENTS",coeff); log.printf(" coefficients of multicolvars %f", coeff[0] ); - for(unsigned i=1;i<coeff.size();++i) log.printf(", %f", coeff[i] ); - log.printf("\n"); + for(unsigned i=1; i<coeff.size(); ++i) log.printf(", %f", coeff[i] ); + log.printf("\n"); } double MultiColvarCombine::compute( const unsigned& tindex, AtomValuePack& myatoms ) const { - double dot=0; std::vector<double> tval(2); - for(unsigned i=0;i<coeff.size();++i){ - getInputData( i, false, myatoms, tval ); - dot += coeff[i]*tval[1]; + double dot=0; std::vector<double> tval(2); + for(unsigned i=0; i<coeff.size(); ++i) { + getInputData( i, false, myatoms, tval ); + dot += coeff[i]*tval[1]; } - if( !doNotCalculateDerivatives() ){ - MultiValue& myvals = myatoms.getUnderlyingMultiValue(); std::vector<double> cc(2); - for(unsigned i=0;i<coeff.size();++i){ - cc[1]=coeff[i]; MultiValue& myder=getInputDerivatives( i, false, myatoms ); - splitInputDerivatives( 1, 1, 2, i, cc, myder, myatoms ); - } + if( !doNotCalculateDerivatives() ) { + MultiValue& myvals = myatoms.getUnderlyingMultiValue(); std::vector<double> cc(2); + for(unsigned i=0; i<coeff.size(); ++i) { + cc[1]=coeff[i]; MultiValue& myder=getInputDerivatives( i, false, myatoms ); + splitInputDerivatives( 1, 1, 2, i, cc, myder, myatoms ); + } } return dot; } diff --git a/src/multicolvar/MultiColvarDensity.cpp b/src/multicolvar/MultiColvarDensity.cpp index 2c022a3be..7ea3dc009 100644 --- a/src/multicolvar/MultiColvarDensity.cpp +++ b/src/multicolvar/MultiColvarDensity.cpp @@ -39,18 +39,18 @@ namespace multicolvar { /* Evaluate the average value of a multicolvar on a grid. -This keyword allows one to construct a phase field representation for a symmetry function from -an atomistic description. If each atom has an associated order parameter, \f$\phi_i\f$ then a +This keyword allows one to construct a phase field representation for a symmetry function from +an atomistic description. If each atom has an associated order parameter, \f$\phi_i\f$ then a smooth phase field function \f$\phi(r)\f$ can be computed using: \f[ \phi(\mathbf{r}) = \frac{\sum_i K(\mathbf{r}-\mathbf{r}_i) \phi_i }{ \sum_i K(\mathbf{r} - \mathbf{r}_i )} \f] -where \f$\mathbf{r}_i\f$ is the position of atom \f$i\f$, the sums run over all the atoms input +where \f$\mathbf{r}_i\f$ is the position of atom \f$i\f$, the sums run over all the atoms input and \f$K(\mathbf{r} - \mathbf{r}_i)\f$ is one of the \ref kernelfunctions implemented in plumed. -This action calculates the above function on a grid, which can then be used in the input to further -actions. +This action calculates the above function on a grid, which can then be used in the input to further +actions. \par Examples @@ -60,13 +60,13 @@ other words this input instructs plumed to calculate \f$\rho(\mathbf{r}) = \sum_ \verbatim dens: DENSITY SPECIES=1-100 -grid: MULTICOLVARDENS DATA=dens ORIGIN=1 DIR=xyz NBINS=100,100,100 BANDWIDTH=0.05,0.05,0.05 STRIDE=1 -DUMPGRID GRID=grid STRIDE=500 FILE=density -\endverbatim +grid: MULTICOLVARDENS DATA=dens ORIGIN=1 DIR=xyz NBINS=100,100,100 BANDWIDTH=0.05,0.05,0.05 STRIDE=1 +DUMPGRID GRID=grid STRIDE=500 FILE=density +\endverbatim -In the above example density is added to the grid on every step. The PRINT_GRID instruction thus tells PLUMED to +In the above example density is added to the grid on every step. The PRINT_GRID instruction thus tells PLUMED to output the average density at each point on the grid every 500 steps of simulation. Notice that the that grid output -on step 1000 is an average over all 1000 frames of the trajectory. If you would like to analyse these two blocks +on step 1000 is an average over all 1000 frames of the trajectory. If you would like to analyse these two blocks of data separately you must use the CLEAR flag. This second example computes an order parameter (in this case \ref FCCUBIC) and constructs a phase field model @@ -74,14 +74,14 @@ for this order parameter using the equation above. \verbatim fcc: FCCUBIC SPECIES=1-5184 SWITCH={CUBIC D_0=1.2 D_MAX=1.5} ALPHA=27 -dens: MULTICOLVARDENS DATA=fcc ORIGIN=1 DIR=xyz NBINS=14,14,28 BANDWIDTH=1.0,1.0,1.0 STRIDE=1 CLEAR=1 +dens: MULTICOLVARDENS DATA=fcc ORIGIN=1 DIR=xyz NBINS=14,14,28 BANDWIDTH=1.0,1.0,1.0 STRIDE=1 CLEAR=1 DUMPCUBE GRID=dens STRIDE=1 FILE=dens.cube \endverbatim In this example the phase field model is computed and output to a file on every step of the simulation. Furthermore, because the CLEAR=1 keyword is set on the MULTICOLVARDENS line each Gaussian cube file output is a phase field -model for a particular trajectory frame. The average value accumulated thus far is cleared at the start of every single -timestep and there is no averaging over trajectory frames in this case. +model for a particular trajectory frame. The average value accumulated thus far is cleared at the start of every single +timestep and there is no averaging over trajectory frames in this case. */ //+ENDPLUMEDOC @@ -100,16 +100,16 @@ public: explicit MultiColvarDensity(const ActionOptions&); static void registerKeywords( Keywords& keys ); unsigned getNumberOfQuantities() const ; - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } void clearAverage(); void prepareForAveraging(); - void compute( const unsigned& , MultiValue& ) const ; - void apply(){} + void compute( const unsigned&, MultiValue& ) const ; + void apply() {} }; PLUMED_REGISTER_ACTION(MultiColvarDensity,"MULTICOLVARDENS") -void MultiColvarDensity::registerKeywords( Keywords& keys ){ +void MultiColvarDensity::registerKeywords( Keywords& keys ) { gridtools::ActionWithGrid::registerKeywords( keys ); keys.add("atoms","ORIGIN","we will use the position of this atom as the origin"); keys.add("compulsory","DATA","the multicolvar which you would like to calculate the density profile for"); @@ -119,24 +119,24 @@ void MultiColvarDensity::registerKeywords( Keywords& keys ){ keys.addFlag("FRACTIONAL",false,"use fractional coordinates for the various axes"); keys.addFlag("XREDUCED",false,"limit the calculation of the density/average to a portion of the z-axis only"); keys.add("optional","XLOWER","this is required if you are using XREDUCED. It specifes the lower bound for the region of the x-axis that for " - "which you are calculating the density/average"); + "which you are calculating the density/average"); keys.add("optional","XUPPER","this is required if you are using XREDUCED. It specifes the upper bound for the region of the x-axis that for " - "which you are calculating the density/average"); + "which you are calculating the density/average"); keys.addFlag("YREDUCED",false,"limit the calculation of the density/average to a portion of the y-axis only"); keys.add("optional","YLOWER","this is required if you are using YREDUCED. It specifes the lower bound for the region of the y-axis that for " - "which you are calculating the density/average"); + "which you are calculating the density/average"); keys.add("optional","YUPPER","this is required if you are using YREDUCED. It specifes the upper bound for the region of the y-axis that for " - "which you are calculating the density/average"); + "which you are calculating the density/average"); keys.addFlag("ZREDUCED",false,"limit the calculation of the density/average to a portion of the z-axis only"); keys.add("optional","ZLOWER","this is required if you are using ZREDUCED. It specifes the lower bound for the region of the z-axis that for " - "which you are calculating the density/average"); + "which you are calculating the density/average"); keys.add("optional","ZUPPER","this is required if you are using ZREDUCED. It specifes the upper bound for the region of the z-axis that for " - "which you are calculating the density/average"); + "which you are calculating the density/average"); } MultiColvarDensity::MultiColvarDensity(const ActionOptions&ao): -Action(ao), -ActionWithGrid(ao) + Action(ao), + ActionWithGrid(ao) { std::vector<AtomNumber> atom; parseAtomList("ORIGIN",atom); @@ -151,82 +151,82 @@ ActionWithGrid(ao) parseFlag("FRACTIONAL",fractional); std::string direction; parse("DIR",direction); log.printf(" calculating for %s density profile along ", mycolv->getLabel().c_str() ); - if( direction=="x" ){ - log.printf("x axis"); - directions.resize(1); directions[0]=0; - } else if( direction=="y" ){ - log.printf("y axis"); - directions.resize(1); directions[0]=1; - } else if( direction=="z" ){ - log.printf("z axis"); - directions.resize(1); directions[0]=2; - } else if( direction=="xy" ){ - log.printf("x and y axes"); - directions.resize(2); directions[0]=0; directions[1]=1; - } else if( direction=="xz" ){ - log.printf("x and z axes"); - directions.resize(2); directions[0]=0; directions[1]=2; - } else if( direction=="yz" ){ - log.printf("y and z axis"); - directions.resize(2); directions[0]=1; directions[1]=2; - } else if( direction=="xyz" ){ - log.printf("x, y and z axes"); - directions.resize(3); directions[0]=0; directions[1]=1; directions[2]=2; + if( direction=="x" ) { + log.printf("x axis"); + directions.resize(1); directions[0]=0; + } else if( direction=="y" ) { + log.printf("y axis"); + directions.resize(1); directions[0]=1; + } else if( direction=="z" ) { + log.printf("z axis"); + directions.resize(1); directions[0]=2; + } else if( direction=="xy" ) { + log.printf("x and y axes"); + directions.resize(2); directions[0]=0; directions[1]=1; + } else if( direction=="xz" ) { + log.printf("x and z axes"); + directions.resize(2); directions[0]=0; directions[1]=2; + } else if( direction=="yz" ) { + log.printf("y and z axis"); + directions.resize(2); directions[0]=1; directions[1]=2; + } else if( direction=="xyz" ) { + log.printf("x, y and z axes"); + directions.resize(3); directions[0]=0; directions[1]=1; directions[2]=2; } else { - error( direction + " is not valid gradient direction"); - } + error( direction + " is not valid gradient direction"); + } log.printf(" for colvars calculated by action %s \n",mycolv->getLabel().c_str() ); parseVector("NBINS",nbins); parseVector("SPACING",gspacing); if( nbins.size()!=directions.size() && gspacing.size()!=directions.size() ) error("NBINS or SPACING must be set"); confined.resize( directions.size() ); cmin.resize( directions.size(), 0 ); cmax.resize( directions.size(), 0 ); - for(unsigned i=0;i<directions.size();++i){ - if( directions[i]==0 ){ - bool tflag; parseFlag("XREDUCED",tflag); confined[i]=tflag; - if( confined[i] ){ - cmin[i]=cmax[i]=0.0; parse("XLOWER",cmin[i]); parse("XUPPER",cmax[i]); - if( fractional ) error("XREDUCED is incompatible with FRACTIONAL"); - if( fabs(cmin[i]-cmax[i])<epsilon ) error("range set for x axis makes no sense"); - log.printf(" confining calculation in x direction to between %f and %f \n",cmin[i],cmax[i]); - } - } else if( directions[i]==1 ){ - bool tflag; parseFlag("YREDUCED",tflag); confined[i]=tflag; - if( confined[i] ){ - cmin[i]=cmax[i]=0.0; parse("YLOWER",cmin[i]); parse("YUPPER",cmax[i]); - if( fractional ) error("YREDUCED is incompatible with FRACTIONAL"); - if( fabs(cmin[i]-cmax[i])<epsilon ) error("range set for y axis makes no sense"); - log.printf(" confining calculation in y direction to between %f and %f \n",cmin[i],cmax[i]); - } - } else if( directions[i]==2 ){ - bool tflag; parseFlag("ZREDUCED",tflag); confined[i]=tflag; - if( confined[i] ){ - cmin[i]=cmax[i]=0.0; parse("ZLOWER",cmin[i]); parse("ZUPPER",cmax[i]); - if( fractional ) error("ZREDUCED is incompatible with FRACTIONAL"); - if( fabs(cmin[i]-cmax[i])<epsilon ) error("range set for z axis search makes no sense"); - log.printf(" confining calculation in z direction to between %f and %f \n",cmin[i],cmax[i]); - } + for(unsigned i=0; i<directions.size(); ++i) { + if( directions[i]==0 ) { + bool tflag; parseFlag("XREDUCED",tflag); confined[i]=tflag; + if( confined[i] ) { + cmin[i]=cmax[i]=0.0; parse("XLOWER",cmin[i]); parse("XUPPER",cmax[i]); + if( fractional ) error("XREDUCED is incompatible with FRACTIONAL"); + if( fabs(cmin[i]-cmax[i])<epsilon ) error("range set for x axis makes no sense"); + log.printf(" confining calculation in x direction to between %f and %f \n",cmin[i],cmax[i]); + } + } else if( directions[i]==1 ) { + bool tflag; parseFlag("YREDUCED",tflag); confined[i]=tflag; + if( confined[i] ) { + cmin[i]=cmax[i]=0.0; parse("YLOWER",cmin[i]); parse("YUPPER",cmax[i]); + if( fractional ) error("YREDUCED is incompatible with FRACTIONAL"); + if( fabs(cmin[i]-cmax[i])<epsilon ) error("range set for y axis makes no sense"); + log.printf(" confining calculation in y direction to between %f and %f \n",cmin[i],cmax[i]); } + } else if( directions[i]==2 ) { + bool tflag; parseFlag("ZREDUCED",tflag); confined[i]=tflag; + if( confined[i] ) { + cmin[i]=cmax[i]=0.0; parse("ZLOWER",cmin[i]); parse("ZUPPER",cmax[i]); + if( fractional ) error("ZREDUCED is incompatible with FRACTIONAL"); + if( fabs(cmin[i]-cmax[i])<epsilon ) error("range set for z axis search makes no sense"); + log.printf(" confining calculation in z direction to between %f and %f \n",cmin[i],cmax[i]); + } + } } - std::string vstring; + std::string vstring; if( confined[0] ) vstring +="PBC=F"; else vstring += " PBC=T"; - for(unsigned i=1;i<directions.size();++i){ - if( confined[i] ) vstring += ",F"; - else vstring += ",T"; + for(unsigned i=1; i<directions.size(); ++i) { + if( confined[i] ) vstring += ",F"; + else vstring += ",T"; } vstring +=" COMPONENTS=" + mycolv->getLabel() + ".dens"; vstring +=" COORDINATES="; if( directions[0]==0 ) vstring+="x"; else if( directions[0]==1 ) vstring+="y"; else if( directions[0]==2 ) vstring+="z"; - for(unsigned i=1;i<directions.size();++i){ + for(unsigned i=1; i<directions.size(); ++i) { if( directions[i]==0 ) vstring+=",x"; else if( directions[i]==1 ) vstring+=",y"; else if( directions[i]==2 ) vstring+=",z"; } // Create a task list - for(unsigned i=0;i<mycolv->getFullNumberOfTasks();++i) addTaskToList(i); + for(unsigned i=0; i<mycolv->getFullNumberOfTasks(); ++i) addTaskToList(i); // And create the grid if( mycolv->isDensity() ) createGrid( "histogram", vstring ); else createGrid( "average", vstring ); @@ -234,12 +234,12 @@ ActionWithGrid(ao) setAveragingAction( mygrid, true ); // Enusre units for cube files are set correctly - if( !fractional ){ - if( plumed.getAtoms().usingNaturalUnits() ) mygrid->setCubeUnits( 1.0/0.5292 ); - else mygrid->setCubeUnits( plumed.getAtoms().getUnits().getLength()/.05929 ); + if( !fractional ) { + if( plumed.getAtoms().usingNaturalUnits() ) mygrid->setCubeUnits( 1.0/0.5292 ); + else mygrid->setCubeUnits( plumed.getAtoms().getUnits().getLength()/.05929 ); } - checkRead(); requestAtoms(atom); + checkRead(); requestAtoms(atom); // Stupid dependencies cleared by requestAtoms - why GBussi why? That's got me so many times addDependency( mycolv ); } @@ -248,49 +248,49 @@ unsigned MultiColvarDensity::getNumberOfQuantities() const { return directions.size() + 2; } -void MultiColvarDensity::clearAverage(){ +void MultiColvarDensity::clearAverage() { std::vector<double> min(directions.size()), max(directions.size()); std::vector<std::string> gmin(directions.size()), gmax(directions.size());; - for(unsigned i=0;i<directions.size();++i){ min[i]=-0.5; max[i]=0.5; } - if( !fractional ){ - if( !mycolv->getPbc().isOrthorombic() ){ - error("I think that density profiles with non-orthorhombic cells don't work. If you want it have a look and see if you can work it out"); - } - - for(unsigned i=0;i<directions.size();++i){ - if( !confined[i] ){ - min[i]*=mycolv->getBox()(directions[i],directions[i]); - max[i]*=mycolv->getBox()(directions[i],directions[i]); - } else { - min[i]=cmin[i]; max[i]=cmax[i]; - } - } + for(unsigned i=0; i<directions.size(); ++i) { min[i]=-0.5; max[i]=0.5; } + if( !fractional ) { + if( !mycolv->getPbc().isOrthorombic() ) { + error("I think that density profiles with non-orthorhombic cells don't work. If you want it have a look and see if you can work it out"); + } + + for(unsigned i=0; i<directions.size(); ++i) { + if( !confined[i] ) { + min[i]*=mycolv->getBox()(directions[i],directions[i]); + max[i]*=mycolv->getBox()(directions[i],directions[i]); + } else { + min[i]=cmin[i]; max[i]=cmax[i]; + } + } } - for(unsigned i=0;i<directions.size();++i){ Tools::convert(min[i],gmin[i]); Tools::convert(max[i],gmax[i]); } + for(unsigned i=0; i<directions.size(); ++i) { Tools::convert(min[i],gmin[i]); Tools::convert(max[i],gmax[i]); } ActionWithAveraging::clearAverage(); mygrid->setBounds( gmin, gmax, nbins, gspacing ); resizeFunctions(); } -void MultiColvarDensity::prepareForAveraging(){ - for(unsigned i=0;i<directions.size();++i){ - if( confined[i] ) continue; - std::string max; Tools::convert( 0.5*mycolv->getBox()(directions[i],directions[i]), max ); - if( max!=mygrid->getMax()[i] ) error("box size should be fixed. Use FRACTIONAL"); +void MultiColvarDensity::prepareForAveraging() { + for(unsigned i=0; i<directions.size(); ++i) { + if( confined[i] ) continue; + std::string max; Tools::convert( 0.5*mycolv->getBox()(directions[i],directions[i]), max ); + if( max!=mygrid->getMax()[i] ) error("box size should be fixed. Use FRACTIONAL"); } // Ensure we only work with active multicolvars deactivateAllTasks(); - for(unsigned i=0;i<stash->getNumberOfStoredValues();++i) taskFlags[i]=1; + for(unsigned i=0; i<stash->getNumberOfStoredValues(); ++i) taskFlags[i]=1; lockContributors(); // Retrieve the origin - origin = getPosition(0); + origin = getPosition(0); } void MultiColvarDensity::compute( const unsigned& current, MultiValue& myvals ) const { std::vector<double> cvals( mycolv->getNumberOfQuantities() ); stash->retrieveSequentialValue( current, false, cvals ); Vector fpos, apos = pbcDistance( origin, mycolv->getCentralAtomPos( mycolv->getPositionInFullTaskList(current) ) ); - if( fractional ){ fpos = getPbc().realToScaled( apos ); } else { fpos=apos; } + if( fractional ) { fpos = getPbc().realToScaled( apos ); } else { fpos=apos; } - myvals.setValue( 0, cweight*cvals[0] ); for(unsigned j=0;j<directions.size();++j) myvals.setValue( 1+j, fpos[ directions[j] ] ); + myvals.setValue( 0, cweight*cvals[0] ); for(unsigned j=0; j<directions.size(); ++j) myvals.setValue( 1+j, fpos[ directions[j] ] ); myvals.setValue( 1+directions.size(), cvals[1] ); } diff --git a/src/multicolvar/MultiColvarFilter.cpp b/src/multicolvar/MultiColvarFilter.cpp index a8ed8e9f9..8d8b0c2be 100644 --- a/src/multicolvar/MultiColvarFilter.cpp +++ b/src/multicolvar/MultiColvarFilter.cpp @@ -24,7 +24,7 @@ namespace PLMD { namespace multicolvar { -void MultiColvarFilter::registerKeywords( Keywords& keys ){ +void MultiColvarFilter::registerKeywords( Keywords& keys ) { BridgedMultiColvarFunction::registerKeywords( keys ); if( keys.reserved("VMEAN") ) keys.use("VMEAN"); keys.use("MEAN"); keys.use("MOMENTS"); keys.use("MIN"); keys.use("MAX"); @@ -32,8 +32,8 @@ void MultiColvarFilter::registerKeywords( Keywords& keys ){ } MultiColvarFilter::MultiColvarFilter(const ActionOptions&ao): -Action(ao), -BridgedMultiColvarFunction(ao) + Action(ao), + BridgedMultiColvarFunction(ao) { if( getPntrToMultiColvar()->isDensity() ) error("filtering/transforming density makes no sense"); @@ -43,10 +43,10 @@ BridgedMultiColvarFunction(ao) filter=false; } - readVesselKeywords(); + readVesselKeywords(); } -void MultiColvarFilter::doJobsRequiredBeforeTaskList(){ +void MultiColvarFilter::doJobsRequiredBeforeTaskList() { ActionWithValue::clearDerivatives(); ActionWithVessel::doJobsRequiredBeforeTaskList(); } @@ -54,39 +54,39 @@ void MultiColvarFilter::doJobsRequiredBeforeTaskList(){ void MultiColvarFilter::completeTask( const unsigned& curr, MultiValue& invals, MultiValue& outvals ) const { invals.copyValues( outvals ); if( derivativesAreRequired() ) invals.copyDerivatives( outvals ); - + // Retrive the value of the multicolvar and apply filter double val=invals.get(1), df, weight=applyFilter( val, df ); // Now propegate derivatives - if( filter && !getPntrToMultiColvar()->weightHasDerivatives ){ - outvals.setValue( 0, weight ); - if( derivativesAreRequired() ){ - for(unsigned i=0;i<invals.getNumberActive();++i){ - unsigned jder=invals.getActiveIndex(i); - outvals.addDerivative( 0, jder, df*invals.getDerivative(1, jder ) ); - } - } + if( filter && !getPntrToMultiColvar()->weightHasDerivatives ) { + outvals.setValue( 0, weight ); + if( derivativesAreRequired() ) { + for(unsigned i=0; i<invals.getNumberActive(); ++i) { + unsigned jder=invals.getActiveIndex(i); + outvals.addDerivative( 0, jder, df*invals.getDerivative(1, jder ) ); + } + } } else if( filter ) { - double ww=outvals.get(0); outvals.setValue( 0, ww*weight ); - if( derivativesAreRequired() ){ - for(unsigned i=0;i<outvals.getNumberActive();++i){ - unsigned ider=outvals.getActiveIndex(i); - outvals.setDerivative( 0, ider, weight*outvals.getDerivative(1,ider) + ww*df*outvals.getDerivative(0,ider) ); - } - } + double ww=outvals.get(0); outvals.setValue( 0, ww*weight ); + if( derivativesAreRequired() ) { + for(unsigned i=0; i<outvals.getNumberActive(); ++i) { + unsigned ider=outvals.getActiveIndex(i); + outvals.setDerivative( 0, ider, weight*outvals.getDerivative(1,ider) + ww*df*outvals.getDerivative(0,ider) ); + } + } } else { - outvals.setValue( 1, weight ); - if( derivativesAreRequired() ){ - for(unsigned i=0;i<invals.getNumberActive();++i){ - unsigned jder=invals.getActiveIndex(i); - outvals.setDerivative( 1, jder, df*invals.getDerivative(1, jder ) ); - } - } + outvals.setValue( 1, weight ); + if( derivativesAreRequired() ) { + for(unsigned i=0; i<invals.getNumberActive(); ++i) { + unsigned jder=invals.getActiveIndex(i); + outvals.setDerivative( 1, jder, df*invals.getDerivative(1, jder ) ); + } + } } } -void MultiColvarFilter::addBridgeForces( const std::vector<double>& bb ){ +void MultiColvarFilter::addBridgeForces( const std::vector<double>& bb ) { plumed_dbg_assert( bb.size()==0 ); } diff --git a/src/multicolvar/MultiColvarFilter.h b/src/multicolvar/MultiColvarFilter.h index 8ad4f58f1..e6310bf10 100644 --- a/src/multicolvar/MultiColvarFilter.h +++ b/src/multicolvar/MultiColvarFilter.h @@ -30,7 +30,7 @@ namespace multicolvar { /** \ingroup INHERIT -This is the abstract base class to use for implementing a new way of filtering collective variable values +This is the abstract base class to use for implementing a new way of filtering collective variable values to see whether or not they are within a certain range */ diff --git a/src/multicolvar/MultiColvarProduct.cpp b/src/multicolvar/MultiColvarProduct.cpp index 627cacc53..c7dd7d2c3 100644 --- a/src/multicolvar/MultiColvarProduct.cpp +++ b/src/multicolvar/MultiColvarProduct.cpp @@ -24,7 +24,7 @@ #include "core/ActionRegister.h" #include <string> -#include <cmath> +#include <cmath> //+PLUMEDOC MCOLVARF MCOLV_PRODUCT /* @@ -46,41 +46,41 @@ public: /// Actually do the calculation double compute( const unsigned& tindex, AtomValuePack& myatoms ) const ; /// Is the variable periodic - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } }; PLUMED_REGISTER_ACTION(MultiColvarProduct,"MCOLV_PRODUCT") -void MultiColvarProduct::registerKeywords( Keywords& keys ){ +void MultiColvarProduct::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); keys.add("compulsory","DATA","the multicolvars you are calculating the product of"); - keys.use("MEAN"); keys.use("MORE_THAN"); keys.use("SUM"); keys.use("LESS_THAN"); keys.use("HISTOGRAM"); keys.use("HISTOGRAM"); + keys.use("MEAN"); keys.use("MORE_THAN"); keys.use("SUM"); keys.use("LESS_THAN"); keys.use("HISTOGRAM"); keys.use("HISTOGRAM"); keys.use("MIN"); keys.use("MAX"); keys.use("LOWEST"); keys.use("HIGHEST"); keys.use("ALT_MIN"); keys.use("BETWEEN"); keys.use("MOMENTS"); } MultiColvarProduct::MultiColvarProduct(const ActionOptions& ao): -Action(ao), -MultiColvarBase(ao) + Action(ao), + MultiColvarBase(ao) { buildSets(); - for(unsigned i=0;i<getNumberOfBaseMultiColvars();++i){ - if( mybasemulticolvars[i]->weightWithDerivatives() ) error("cannot take product of multicolvars with weights"); + for(unsigned i=0; i<getNumberOfBaseMultiColvars(); ++i) { + if( mybasemulticolvars[i]->weightWithDerivatives() ) error("cannot take product of multicolvars with weights"); } } double MultiColvarProduct::compute( const unsigned& tindex, AtomValuePack& myatoms ) const { - double dot=1; std::vector<double> tval(2); - for(unsigned i=0;i<getNumberOfBaseMultiColvars();++i){ - getInputData( i, false, myatoms, tval ); - dot *= tval[1]; + double dot=1; std::vector<double> tval(2); + for(unsigned i=0; i<getNumberOfBaseMultiColvars(); ++i) { + getInputData( i, false, myatoms, tval ); + dot *= tval[1]; } - if( !doNotCalculateDerivatives() ){ - MultiValue& myvals = myatoms.getUnderlyingMultiValue(); std::vector<double> cc(2); - for(unsigned i=0;i<getNumberOfBaseMultiColvars();++i){ - getInputData( i, false, myatoms, cc ); cc[1] = dot / cc[1]; - MultiValue& myder=getInputDerivatives( i, false, myatoms ); - splitInputDerivatives( 1, 1, 2, i, cc, myder, myatoms ); - } + if( !doNotCalculateDerivatives() ) { + MultiValue& myvals = myatoms.getUnderlyingMultiValue(); std::vector<double> cc(2); + for(unsigned i=0; i<getNumberOfBaseMultiColvars(); ++i) { + getInputData( i, false, myatoms, cc ); cc[1] = dot / cc[1]; + MultiValue& myder=getInputDerivatives( i, false, myatoms ); + splitInputDerivatives( 1, 1, 2, i, cc, myder, myatoms ); + } } return dot; } diff --git a/src/multicolvar/NumberOfLinks.cpp b/src/multicolvar/NumberOfLinks.cpp index fb39149e6..b8257c5e4 100644 --- a/src/multicolvar/NumberOfLinks.cpp +++ b/src/multicolvar/NumberOfLinks.cpp @@ -25,16 +25,16 @@ #include "tools/SwitchingFunction.h" #include <string> -#include <cmath> +#include <cmath> -//+PLUMEDOC MCOLVARF NLINKS +//+PLUMEDOC MCOLVARF NLINKS /* Calculate number of pairs of atoms/molecules that are "linked" In its simplest guise this coordinate calculates a coordination number. Each pair -of atoms is assumed "linked" if they are within some cutoff of each other. In more +of atoms is assumed "linked" if they are within some cutoff of each other. In more complex applications each entity is a vector and this quantity measures whether -pairs of vectors are (a) within a certain cutoff and (b) if the two vectors have +pairs of vectors are (a) within a certain cutoff and (b) if the two vectors have similar orientations. The vectors on individual atoms could be Steinhardt parameters (see \ref Q3, \ref Q4 and \ref Q6) or they could describe some internal vector in a molecule. @@ -50,7 +50,7 @@ PRINT ARG=dd FILE=colvar \endverbatim The following calculates how many pairs of neighbouring atoms in a system containg 64 atoms have -similar dispositions for the atoms in their coordination sphere. This calculation uses the +similar dispositions for the atoms in their coordination sphere. This calculation uses the dot product of the Q6 vectors on adjacent atoms to measure whether or not two atoms have the same ``orientation" @@ -58,7 +58,7 @@ dot product of the Q6 vectors on adjacent atoms to measure whether or not two at Q6 SPECIES=1-64 SWITCH={RATIONAL D_0=1.3 R_0=0.2} LABEL=q6 NLINKS ARG=q6 SWITCH={RATIONAL D_0=1.3 R_0=0.2} LABEL=dd PRINT ARG=dd FILE=colvar -\endverbatim +\endverbatim */ //+ENDPLUMEDOC @@ -69,7 +69,7 @@ namespace multicolvar { class NumberOfLinks : public MultiColvarBase { private: /// The values of the quantities in the dot products - std::vector<double> orient0, orient1; + std::vector<double> orient0, orient1; /// The switching function that tells us if atoms are close enough together SwitchingFunction switchingFunction; public: @@ -80,12 +80,12 @@ public: /// Actually do the calculation double compute( const unsigned& tindex, AtomValuePack& myatoms ) const ; /// Is the variable periodic - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } }; PLUMED_REGISTER_ACTION(NumberOfLinks,"NLINKS") -void NumberOfLinks::registerKeywords( Keywords& keys ){ +void NumberOfLinks::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); keys.add("atoms","GROUP",""); keys.add("atoms-1","GROUPA",""); @@ -95,36 +95,36 @@ void NumberOfLinks::registerKeywords( Keywords& keys ){ keys.add("compulsory","D_0","0.0","The d_0 parameter of the switching function"); keys.add("compulsory","R_0","The r_0 parameter of the switching function"); keys.add("optional","SWITCH","This keyword is used if you want to employ an alternative to the continuous swiching function defined above. " - "The following provides information on the \\ref switchingfunction that are available. " - "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); + "The following provides information on the \\ref switchingfunction that are available. " + "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); // Use actionWithDistributionKeywords - keys.remove("LOWMEM"); + keys.remove("LOWMEM"); keys.addFlag("LOWMEM",false,"lower the memory requirements"); } NumberOfLinks::NumberOfLinks(const ActionOptions& ao): -Action(ao), -MultiColvarBase(ao) + Action(ao), + MultiColvarBase(ao) { // The weight of this does have derivatives weightHasDerivatives=true; // Read in the switching function std::string sw, errors; parse("SWITCH",sw); - if(sw.length()>0){ - switchingFunction.set(sw,errors); + if(sw.length()>0) { + switchingFunction.set(sw,errors); } else { - double r_0=-1.0, d_0; int nn, mm; - parse("NN",nn); parse("MM",mm); - parse("R_0",r_0); parse("D_0",d_0); - if( r_0<0.0 ) error("you must set a value for R_0"); - switchingFunction.set(nn,mm,r_0,d_0); + double r_0=-1.0, d_0; int nn, mm; + parse("NN",nn); parse("MM",mm); + parse("R_0",r_0); parse("D_0",d_0); + if( r_0<0.0 ) error("you must set a value for R_0"); + switchingFunction.set(nn,mm,r_0,d_0); } log.printf(" calculating number of links with atoms separation of %s\n",( switchingFunction.description() ).c_str() ); - std::vector<AtomNumber> all_atoms; readTwoGroups( "GROUP", "GROUPA", "GROUPB", all_atoms ); - setupMultiColvarBase( all_atoms ); setLinkCellCutoff( switchingFunction.get_dmax() ); + std::vector<AtomNumber> all_atoms; readTwoGroups( "GROUP", "GROUPA", "GROUPB", all_atoms ); + setupMultiColvarBase( all_atoms ); setLinkCellCutoff( switchingFunction.get_dmax() ); - for(unsigned i=0;i<getNumberOfBaseMultiColvars();++i){ + for(unsigned i=0; i<getNumberOfBaseMultiColvars(); ++i) { if( !getBaseMultiColvar(i)->hasDifferentiableOrientation() ) error("cannot use multicolvar of type " + getBaseMultiColvar(i)->getName() ); } @@ -139,36 +139,36 @@ double NumberOfLinks::calculateWeight( const unsigned& taskCode, const double& w Vector distance = getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); double dfunc, sw = switchingFunction.calculateSqr( distance.modulo2(), dfunc ); - if( !doNotCalculateDerivatives() ){ - addAtomDerivatives( 0, 0, (-dfunc)*weight*distance, myatoms ); - addAtomDerivatives( 0, 1, (dfunc)*weight*distance, myatoms ); - myatoms.addBoxDerivatives( 0, (-dfunc)*weight*Tensor(distance,distance) ); + if( !doNotCalculateDerivatives() ) { + addAtomDerivatives( 0, 0, (-dfunc)*weight*distance, myatoms ); + addAtomDerivatives( 0, 1, (dfunc)*weight*distance, myatoms ); + myatoms.addBoxDerivatives( 0, (-dfunc)*weight*Tensor(distance,distance) ); } return sw; } double NumberOfLinks::compute( const unsigned& tindex, AtomValuePack& myatoms ) const { - if( getBaseMultiColvar(0)->getNumberOfQuantities()<3 ) return 1.0; + if( getBaseMultiColvar(0)->getNumberOfQuantities()<3 ) return 1.0; - unsigned ncomp=getBaseMultiColvar(0)->getNumberOfQuantities(); + unsigned ncomp=getBaseMultiColvar(0)->getNumberOfQuantities(); - std::vector<double> orient0( ncomp ), orient1( ncomp ); - getInputData( 0, true, myatoms, orient0 ); - getInputData( 1, true, myatoms, orient1 ); + std::vector<double> orient0( ncomp ), orient1( ncomp ); + getInputData( 0, true, myatoms, orient0 ); + getInputData( 1, true, myatoms, orient1 ); - double dot=0; - for(unsigned k=2;k<orient0.size();++k){ - dot+=orient0[k]*orient1[k]; - } + double dot=0; + for(unsigned k=2; k<orient0.size(); ++k) { + dot+=orient0[k]*orient1[k]; + } - if( !doNotCalculateDerivatives() ){ - MultiValue& myder0=getInputDerivatives( 0, true, myatoms ); - mergeInputDerivatives( 1, 2, orient1.size(), 0, orient1, myder0, myatoms ); - MultiValue& myder1=getInputDerivatives( 1, true, myatoms ); - mergeInputDerivatives( 1, 2, orient0.size(), 1, orient0, myder1, myatoms ); - } + if( !doNotCalculateDerivatives() ) { + MultiValue& myder0=getInputDerivatives( 0, true, myatoms ); + mergeInputDerivatives( 1, 2, orient1.size(), 0, orient1, myder0, myatoms ); + MultiValue& myder1=getInputDerivatives( 1, true, myatoms ); + mergeInputDerivatives( 1, 2, orient0.size(), 1, orient0, myder1, myatoms ); + } - return dot; + return dot; } } diff --git a/src/multicolvar/Torsions.cpp b/src/multicolvar/Torsions.cpp index 6143fe6f7..59d02cbfd 100644 --- a/src/multicolvar/Torsions.cpp +++ b/src/multicolvar/Torsions.cpp @@ -29,8 +29,8 @@ using namespace std; -namespace PLMD{ -namespace multicolvar{ +namespace PLMD { +namespace multicolvar { //+PLUMEDOC MCOLVAR TORSIONS /* @@ -44,14 +44,14 @@ The following provides an example of the input for the torsions command TORSIONS ... ATOMS1=168,170,172,188 ATOMS2=170,172,188,190 -ATOMS3=188,190,192,230 +ATOMS3=188,190,192,230 LABEL=ab ... TORSIONS PRINT ARG=ab.* FILE=colvar STRIDE=10 \endverbatim Writing out the atoms involved in all the torsions in this way can be rather tedious. Thankfully if you are working with protein you -can avoid this by using the \ref MOLINFO command. PLUMED uses the pdb file that you provide to this command to learn +can avoid this by using the \ref MOLINFO command. PLUMED uses the pdb file that you provide to this command to learn about the topology of the protein molecule. This means that you can specify torsion angles using the following syntax: \verbatim @@ -61,11 +61,11 @@ ATOMS1=@phi-3 ATOMS2=@psi-3 ATOMS3=@phi-4 LABEL=ab -... TORSIONS +... TORSIONS PRINT ARG=ab FILE=colvar STRIDE=10 \endverbatim -Here, \@phi-3 tells plumed that you would like to calculate the \f$\phi\f$ angle in the third residue of the protein. +Here, \@phi-3 tells plumed that you would like to calculate the \f$\phi\f$ angle in the third residue of the protein. Similarly \@psi-4 tells plumed that you want to calculate the \f$\psi\f$ angle of the 4th residue of the protein. @@ -77,36 +77,36 @@ public: static void registerKeywords( Keywords& keys ); explicit Torsions(const ActionOptions&); virtual double compute( const unsigned& tindex, AtomValuePack& myatoms ) const ; - bool isPeriodic(){ return true; } - void retrieveDomain( std::string& min, std::string& max ){ min="-pi"; max="pi"; } + bool isPeriodic() { return true; } + void retrieveDomain( std::string& min, std::string& max ) { min="-pi"; max="pi"; } }; PLUMED_REGISTER_ACTION(Torsions,"TORSIONS") -void Torsions::registerKeywords( Keywords& keys ){ +void Torsions::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); keys.reserve("numbered","ATOMS","the atoms involved in each of the torsion angles you wish to calculate. " - "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one torsion will be " - "calculated for each ATOM keyword you specify (all ATOM keywords should " - "provide the indices of four atoms). The eventual number of quantities calculated by this " - "action will depend on what functions of the distribution you choose to calculate."); + "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one torsion will be " + "calculated for each ATOM keyword you specify (all ATOM keywords should " + "provide the indices of four atoms). The eventual number of quantities calculated by this " + "action will depend on what functions of the distribution you choose to calculate."); keys.reset_style("ATOMS","atoms"); keys.use("BETWEEN"); keys.use("HISTOGRAM"); } Torsions::Torsions(const ActionOptions&ao): -Action(ao), -MultiColvarBase(ao) + Action(ao), + MultiColvarBase(ao) { // Read in the atoms - int natoms=4; std::vector<AtomNumber> all_atoms; + int natoms=4; std::vector<AtomNumber> all_atoms; readAtomsLikeKeyword( "ATOMS", natoms, all_atoms ); setupMultiColvarBase( all_atoms ); - std::vector<bool> catom_ind(4, false); + std::vector<bool> catom_ind(4, false); catom_ind[1]=catom_ind[2]=true; setAtomsForCentralAtom( catom_ind ); // Read in the vessels - readVesselKeywords(); + readVesselKeywords(); // And check everything has been read in correctly checkRead(); } diff --git a/src/multicolvar/VolumeAround.cpp b/src/multicolvar/VolumeAround.cpp index 69bbfd62c..bab79d8e0 100644 --- a/src/multicolvar/VolumeAround.cpp +++ b/src/multicolvar/VolumeAround.cpp @@ -25,31 +25,31 @@ //+PLUMEDOC VOLUMES AROUND /* -This quantity can be used to calculate functions of the distribution of collective +This quantity can be used to calculate functions of the distribution of collective variables for the atoms that lie in a particular, user-specified part of of the cell. -Each of the base quantities calculated by a multicolvar can can be assigned to a particular point in three +Each of the base quantities calculated by a multicolvar can can be assigned to a particular point in three dimensional space. For example, if we have the coordination numbers for all the atoms in the -system each coordination number can be assumed to lie on the position of the central atom. +system each coordination number can be assumed to lie on the position of the central atom. Because each base quantity can be assigned to a particular point in space we can calculate functions of the distribution of base quantities in a particular part of the box by using: \f[ -\overline{s}_{\tau} = \frac{ \sum_i f(s_i) w(x_i,y_i,z_i) }{ \sum_i w(x_i,y_i,z_i) } -\f] +\overline{s}_{\tau} = \frac{ \sum_i f(s_i) w(x_i,y_i,z_i) }{ \sum_i w(x_i,y_i,z_i) } +\f] where the sum is over the collective variables, \f$s_i\f$, each of which can be thought to be at \f$ (x_i,y_i,z_i)\f$. The function \f$ w(x_i,y_i,z_i) \f$ measures whether or not the system is in the subregion of interest. It is equal to: \f[ -w(x_i,y_i,z_i) = \int_{xl}^{xu} \int_{yl}^{yu} \int_{zl}^{zu} \textrm{d}x\textrm{d}y\textrm{d}z K\left( \frac{x - x_i}{\sigma} \right)K\left( \frac{y - y_i}{\sigma} \right)K\left( \frac{z - z_i}{\sigma} \right) +w(x_i,y_i,z_i) = \int_{xl}^{xu} \int_{yl}^{yu} \int_{zl}^{zu} \textrm{d}x\textrm{d}y\textrm{d}z K\left( \frac{x - x_i}{\sigma} \right)K\left( \frac{y - y_i}{\sigma} \right)K\left( \frac{z - z_i}{\sigma} \right) \f] where \f$K\f$ is one of the kernel functions described on \ref histogrambead and \f$\sigma\f$ is a bandwidth parameter. The function \f$(s_i)\f$ can be any of the usual LESS_THAN, MORE_THAN, WITHIN etc that are used in all other multicolvars. -When AROUND is used with the \ref DENSITY action the number of atoms in the specified region is calculated +When AROUND is used with the \ref DENSITY action the number of atoms in the specified region is calculated \par Examples @@ -79,11 +79,11 @@ public: explicit VolumeAround(const ActionOptions& ao); void setupRegions(); double calculateNumberInside( const Vector& cpos, Vector& derivatives, Tensor& vir, std::vector<Vector>& refders ) const ; -}; +}; PLUMED_REGISTER_ACTION(VolumeAround,"AROUND") -void VolumeAround::registerKeywords( Keywords& keys ){ +void VolumeAround::registerKeywords( Keywords& keys ) { ActionVolume::registerKeywords( keys ); keys.add("atoms","ATOM","the atom whose vicinity we are interested in examining"); keys.add("compulsory","XLOWER","0.0","the lower boundary in x relative to the x coordinate of the atom (0 indicates use full extent of box)."); @@ -95,10 +95,10 @@ void VolumeAround::registerKeywords( Keywords& keys ){ } VolumeAround::VolumeAround(const ActionOptions& ao): -Action(ao), -ActionVolume(ao) + Action(ao), + ActionVolume(ao) { - std::vector<AtomNumber> atom; + std::vector<AtomNumber> atom; parseAtomList("ATOM",atom); if( atom.size()!=1 ) error("should only be one atom specified"); log.printf(" boundaries for region are calculated based on positions of atom : %d\n",atom[0].serial() ); @@ -108,13 +108,13 @@ ActionVolume(ao) doz=true; parse("ZLOWER",zlow); parse("ZUPPER",zhigh); if( xlow==0.0 && xhigh==0.0 ) dox=false; if( ylow==0.0 && yhigh==0.0 ) doy=false; - if( zlow==0.0 && zhigh==0.0 ) doz=false; + if( zlow==0.0 && zhigh==0.0 ) doz=false; if( !dox && !doy && !doz ) error("no subregion defined use XLOWER, XUPPER, YLOWER, YUPPER, ZLOWER, ZUPPER"); log.printf(" boundaries for region (region of interest about atom) : x %f %f, y %f %f, z %f %f \n",xlow,xhigh,ylow,yhigh,zlow,zhigh); - checkRead(); requestAtoms(atom); + checkRead(); requestAtoms(atom); } -void VolumeAround::setupRegions(){ } +void VolumeAround::setupRegions() { } double VolumeAround::calculateNumberInside( const Vector& cpos, Vector& derivatives, Tensor& vir, std::vector<Vector>& refders ) const { // Setup the histogram bead @@ -122,27 +122,27 @@ double VolumeAround::calculateNumberInside( const Vector& cpos, Vector& derivati // Calculate position of atom wrt to origin Vector fpos=pbcDistance( getPosition(0), cpos ); - double xcontr, ycontr, zcontr, xder, yder, zder; - if( dox ){ - bead.set( xlow, xhigh, getSigma() ); - xcontr=bead.calculate( fpos[0], xder ); + double xcontr, ycontr, zcontr, xder, yder, zder; + if( dox ) { + bead.set( xlow, xhigh, getSigma() ); + xcontr=bead.calculate( fpos[0], xder ); } else { - xcontr=1.; xder=0.; + xcontr=1.; xder=0.; } - if( doy ){ - bead.set( ylow, yhigh, getSigma() ); - ycontr=bead.calculate( fpos[1], yder ); + if( doy ) { + bead.set( ylow, yhigh, getSigma() ); + ycontr=bead.calculate( fpos[1], yder ); } else { - ycontr=1.; yder=0.; + ycontr=1.; yder=0.; } - if( doz ){ - bead.set( zlow, zhigh, getSigma() ); - zcontr=bead.calculate( fpos[2], zder ); + if( doz ) { + bead.set( zlow, zhigh, getSigma() ); + zcontr=bead.calculate( fpos[2], zder ); } else { - zcontr=1.; zder=0.; + zcontr=1.; zder=0.; } - derivatives[0]=xder*ycontr*zcontr; - derivatives[1]=xcontr*yder*zcontr; + derivatives[0]=xder*ycontr*zcontr; + derivatives[1]=xcontr*yder*zcontr; derivatives[2]=xcontr*ycontr*zder; // Add derivatives wrt to position of origin atom refders[0] = -derivatives; diff --git a/src/multicolvar/VolumeCavity.cpp b/src/multicolvar/VolumeCavity.cpp index 65c232a90..af14a2be0 100644 --- a/src/multicolvar/VolumeCavity.cpp +++ b/src/multicolvar/VolumeCavity.cpp @@ -28,22 +28,22 @@ //+PLUMEDOC VOLUMES CAVITY /* -This quantity can be used to calculate functions of the distribution of collective +This quantity can be used to calculate functions of the distribution of collective variables for the atoms that lie in a box defined by the positions of four atoms. -Each of the base quantities calculated by a multicolvar can can be assigned to a particular point in three +Each of the base quantities calculated by a multicolvar can can be assigned to a particular point in three dimensional space. For example, if we have the coordination numbers for all the atoms in the -system each coordination number can be assumed to lie on the position of the central atom. +system each coordination number can be assumed to lie on the position of the central atom. Because each base quantity can be assigned to a particular point in space we can calculate functions of the distribution of base quantities in a particular part of the box by using: \f[ -\overline{s}_{\tau} = \frac{ \sum_i f(s_i) w(u_i,v_i,w_i) }{ \sum_i w(u_i,v_i,w_i) } -\f] +\overline{s}_{\tau} = \frac{ \sum_i f(s_i) w(u_i,v_i,w_i) }{ \sum_i w(u_i,v_i,w_i) } +\f] where the sum is over the collective variables, \f$s_i\f$, each of which can be thought to be at \f$ (u_i,v_i,z_i)\f$. The function \f$(s_i)\f$ can be any of the usual LESS_THAN, MORE_THAN, WITHIN etc that are used in all other multicolvars. -Notice that here (at variance with what is done in \ref AROUND) we have transformed from the usual \f$(x_i,y_i,z_i)\f$ +Notice that here (at variance with what is done in \ref AROUND) we have transformed from the usual \f$(x_i,y_i,z_i)\f$ position to a position in \f$ (u_i,v_i,z_i)\f$. This is done using a rotation matrix as follows: \f[ @@ -63,23 +63,23 @@ position to a position in \f$ (u_i,v_i,z_i)\f$. This is done using a rotation m \right) \f] -where \f$\mathbf{R}\f$ is a rotation matrix that is calculated by constructing a set of three orthonormal vectors from the -refererence positions specified by the user. The first of these unit vectors points from the first reference atom to the second. -The second is then the normal to the plane containing atoms 1,2 and 3 and the the third is the unit vector orthogonal to -these first two vectors. \f$(x_o,y_o,z_o)\f$, meanwhile, specifies the position of the first reference atom. +where \f$\mathbf{R}\f$ is a rotation matrix that is calculated by constructing a set of three orthonormal vectors from the +refererence positions specified by the user. The first of these unit vectors points from the first reference atom to the second. +The second is then the normal to the plane containing atoms 1,2 and 3 and the the third is the unit vector orthogonal to +these first two vectors. \f$(x_o,y_o,z_o)\f$, meanwhile, specifies the position of the first reference atom. In the previous function \f$ w(u_i,v_i,w_i) \f$ measures whether or not the system is in the subregion of interest. It is equal to: \f[ -w(u_i,v_i,w_i) = \int_{0}^{u'} \int_{0}^{v'} \int_{0}^{w'} \textrm{d}u\textrm{d}v\textrm{d}w - K\left( \frac{u - u_i}{\sigma} \right)K\left( \frac{v - v_i}{\sigma} \right)K\left( \frac{w - w_i}{\sigma} \right) +w(u_i,v_i,w_i) = \int_{0}^{u'} \int_{0}^{v'} \int_{0}^{w'} \textrm{d}u\textrm{d}v\textrm{d}w + K\left( \frac{u - u_i}{\sigma} \right)K\left( \frac{v - v_i}{\sigma} \right)K\left( \frac{w - w_i}{\sigma} \right) \f] where \f$K\f$ is one of the kernel functions described on \ref histogrambead and \f$\sigma\f$ is a bandwidth parameter. -The vector connecting atom 1 to atom 4 is used to define the extent of the box in each of the \f$u\f$, \f$v\f$ and \f$w\f$ +The vector connecting atom 1 to atom 4 is used to define the extent of the box in each of the \f$u\f$, \f$v\f$ and \f$w\f$ directions. Essentially the vector connecting atom 1 to atom 4 is projected onto the three unit vectors -described above and the resulting projections determine the \f$u'\f$, \f$v'\f$ and \f$w'\f$ parameters in the above expression. +described above and the resulting projections determine the \f$u'\f$, \f$v'\f$ and \f$w'\f$ parameters in the above expression. \par Examples @@ -87,11 +87,11 @@ The following commands tell plumed to calculate the number of atoms in an ion ch The extent of the chanel is calculated from the positions of atoms 1, 4, 5 and 11. The final value will be labeled cav. \verbatim -d1: DENSITY SPECIES=20-500 +d1: DENSITY SPECIES=20-500 CAVITY DATA=d1 ATOMS=1,4,5,11 SIGMA=0.1 LABEL=cav \endverbatim -The following command tells plumed to calculate the coordination numbers (with other water molecules) for the water +The following command tells plumed to calculate the coordination numbers (with other water molecules) for the water molecules in the protein channel described above. The average coordination number and the number of coordination numbers more than 4 is then calculated. The values of these two quantities are given the labels cav.mean and cav.morethan @@ -127,7 +127,7 @@ public: PLUMED_REGISTER_ACTION(VolumeCavity,"CAVITY") -void VolumeCavity::registerKeywords( Keywords& keys ){ +void VolumeCavity::registerKeywords( Keywords& keys ) { ActionVolume::registerKeywords( keys ); keys.add("atoms","ATOMS","the positions of four atoms that define spatial extent of the cavity"); keys.addFlag("PRINT_BOX",false,"write out the positions of the corners of the box to an xyz file"); @@ -136,54 +136,54 @@ void VolumeCavity::registerKeywords( Keywords& keys ){ } VolumeCavity::VolumeCavity(const ActionOptions& ao): -Action(ao), -ActionVolume(ao), -boxout(false), -lenunit(1.0), -dlbi(4), -dlcross(4), -dlperp(4), -dbi(3), -dcross(3), -dperp(3) + Action(ao), + ActionVolume(ao), + boxout(false), + lenunit(1.0), + dlbi(4), + dlcross(4), + dlperp(4), + dbi(3), + dcross(3), + dperp(3) { std::vector<AtomNumber> atoms; parseAtomList("ATOMS",atoms); if( atoms.size()!=4 ) error("number of atoms should be equal to four"); log.printf(" boundaries for region are calculated based on positions of atoms : "); - for(unsigned i=0;i<atoms.size();++i) log.printf("%d ",atoms[i].serial() ); + for(unsigned i=0; i<atoms.size(); ++i) log.printf("%d ",atoms[i].serial() ); log.printf("\n"); boxout=false; parseFlag("PRINT_BOX",boxout); - if(boxout){ - std::string boxfname; parse("FILE",boxfname); - if(boxfname.length()==0) error("no name for box file specified"); - std::string unitname; parse("UNITS",unitname); - if ( unitname.length()>0 ){ - Units u; u.setLength(unitname); - lenunit=plumed.getAtoms().getUnits().getLength()/u.getLength(); - } else { - unitname="nm"; - } - boxfile.link(*this); - boxfile.open( boxfname.c_str() ); - log.printf(" printing box coordinates on file named %s in %s \n",boxfname.c_str(), unitname.c_str() ); - } + if(boxout) { + std::string boxfname; parse("FILE",boxfname); + if(boxfname.length()==0) error("no name for box file specified"); + std::string unitname; parse("UNITS",unitname); + if ( unitname.length()>0 ) { + Units u; u.setLength(unitname); + lenunit=plumed.getAtoms().getUnits().getLength()/u.getLength(); + } else { + unitname="nm"; + } + boxfile.link(*this); + boxfile.open( boxfname.c_str() ); + log.printf(" printing box coordinates on file named %s in %s \n",boxfname.c_str(), unitname.c_str() ); + } checkRead(); requestAtoms(atoms); // We have to readd the dependency because requestAtoms removes it - addDependency( getPntrToMultiColvar() ); + addDependency( getPntrToMultiColvar() ); } -VolumeCavity::~VolumeCavity(){ +VolumeCavity::~VolumeCavity() { } -void VolumeCavity::setupRegions(){ +void VolumeCavity::setupRegions() { // Make some space for things Vector d1, d2, d3; - + // Retrieve the sigma value sigma=getSigma(); // Set the position of the origin @@ -194,21 +194,21 @@ void VolumeCavity::setupRegions(){ double d1l=d1.modulo(); d2 = pbcDistance(origin,getPosition(2)); - // Find the vector connecting the origin to the top corner of + // Find the vector connecting the origin to the top corner of // the subregion d3 = pbcDistance(origin,getPosition(3)); // Create a set of unit vectors bi = d1 / d1l; len_bi=dotProduct( d3, bi ); - cross = crossProduct( d1, d2 ); double crossmod=cross.modulo(); + cross = crossProduct( d1, d2 ); double crossmod=cross.modulo(); cross = cross / crossmod; len_cross=dotProduct( d3, cross ); perp = crossProduct( cross, bi ); len_perp=dotProduct( d3, perp ); // Calculate derivatives of box shape with respect to atoms - double d1l3=d1l*d1l*d1l; + double d1l3=d1l*d1l*d1l; dbi[0](0,0) = ( -(d1[1]*d1[1]+d1[2]*d1[2])/d1l3 ); // dx/dx dbi[0](0,1) = ( d1[0]*d1[1]/d1l3 ); // dx/dy - dbi[0](0,2) = ( d1[0]*d1[2]/d1l3 ); // dx/dz + dbi[0](0,2) = ( d1[0]*d1[2]/d1l3 ); // dx/dz dbi[0](1,0) = ( d1[1]*d1[0]/d1l3 ); // dy/dx dbi[0](1,1) = ( -(d1[0]*d1[0]+d1[2]*d1[2])/d1l3 ); // dy/dy dbi[0](1,2) = ( d1[1]*d1[2]/d1l3 ); @@ -233,7 +233,7 @@ void VolumeCavity::setupRegions(){ tcderiv.setCol( 2, crossProduct( d1, Vector(0.0,0.0,-1.0) ) + crossProduct( Vector(0.0,0.0,-1.0), d2 ) ); dcross[0](0,0)=( tcderiv(0,0)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 ); // dx/dx dcross[0](0,1)=( tcderiv(0,1)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 ); // dx/dy - dcross[0](0,2)=( tcderiv(0,2)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 ); // dx/dz + dcross[0](0,2)=( tcderiv(0,2)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 ); // dx/dz dcross[0](1,0)=( tcderiv(1,0)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 ); // dy/dx dcross[0](1,1)=( tcderiv(1,1)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 ); // dy/dy dcross[0](1,2)=( tcderiv(1,2)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 ); // dy/dz @@ -246,7 +246,7 @@ void VolumeCavity::setupRegions(){ tcderiv.setCol( 2, crossProduct( Vector(0.0,0.0,1.0), d2 ) ); dcross[1](0,0)=( tcderiv(0,0)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 ); // dx/dx dcross[1](0,1)=( tcderiv(0,1)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 ); // dx/dy - dcross[1](0,2)=( tcderiv(0,2)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 ); // dx/dz + dcross[1](0,2)=( tcderiv(0,2)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 ); // dx/dz dcross[1](1,0)=( tcderiv(1,0)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 ); // dy/dx dcross[1](1,1)=( tcderiv(1,1)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 ); // dy/dy dcross[1](1,2)=( tcderiv(1,2)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 ); // dy/dz @@ -259,7 +259,7 @@ void VolumeCavity::setupRegions(){ tcderiv.setCol( 2, crossProduct( d1, Vector(0.0,0.0,1.0) ) ); dcross[2](0,0)=( tcderiv(0,0)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 ); // dx/dx dcross[2](0,1)=( tcderiv(0,1)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 ); // dx/dy - dcross[2](0,2)=( tcderiv(0,2)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 ); // dx/dz + dcross[2](0,2)=( tcderiv(0,2)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 ); // dx/dz dcross[2](1,0)=( tcderiv(1,0)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 ); // dy/dx dcross[2](1,1)=( tcderiv(1,1)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 ); // dy/dy dcross[2](1,2)=( tcderiv(1,2)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 ); // dy/dz @@ -280,33 +280,33 @@ void VolumeCavity::setupRegions(){ dperp[2].setCol( 2, ( crossProduct( dcross[2].getCol(2), bi ) ) ); // Ensure that all lengths are positive - if( len_bi<0 ){ - bi=-bi; len_bi=-len_bi; - for(unsigned i=0;i<3;++i) dbi[i]*=-1.0; + if( len_bi<0 ) { + bi=-bi; len_bi=-len_bi; + for(unsigned i=0; i<3; ++i) dbi[i]*=-1.0; } - if( len_cross<0 ){ - cross=-cross; len_cross=-len_cross; - for(unsigned i=0;i<3;++i) dcross[i]*=-1.0; + if( len_cross<0 ) { + cross=-cross; len_cross=-len_cross; + for(unsigned i=0; i<3; ++i) dcross[i]*=-1.0; + } + if( len_perp<0 ) { + perp=-perp; len_perp=-len_perp; + for(unsigned i=0; i<3; ++i) dperp[i]*=-1.0; } - if( len_perp<0 ){ - perp=-perp; len_perp=-len_perp; - for(unsigned i=0;i<3;++i) dperp[i]*=-1.0; - } if( len_bi<=0 || len_cross<=0 || len_bi<=0 ) plumed_merror("Invalid box coordinates"); // Now derivatives of lengths - Tensor dd3( Tensor::identity() ); - dlbi[0] = matmul(d3,dbi[0]) - matmul(bi,dd3); + Tensor dd3( Tensor::identity() ); + dlbi[0] = matmul(d3,dbi[0]) - matmul(bi,dd3); dlbi[1] = matmul(d3,dbi[1]); dlbi[2] = matmul(d3,dbi[2]); dlbi[3] = matmul(bi,dd3); - dlcross[0] = matmul(d3,dcross[0]) - matmul(cross,dd3); + dlcross[0] = matmul(d3,dcross[0]) - matmul(cross,dd3); dlcross[1] = matmul(d3,dcross[1]); dlcross[2] = matmul(d3,dcross[2]); dlcross[3] = matmul(cross,dd3); - dlperp[0] = matmul(d3,dperp[0]) - matmul(perp,dd3); + dlperp[0] = matmul(d3,dperp[0]) - matmul(perp,dd3); dlperp[1] = matmul(d3,dperp[1]); dlperp[2] = matmul(d3,dperp[2]); dlperp[3] = matmul(perp,dd3); @@ -319,39 +319,39 @@ void VolumeCavity::setupRegions(){ jacob_det = fabs( jacob.determinant() ); } -void VolumeCavity::update(){ - if(boxout){ - boxfile.printf("%d\n",8); - const Tensor & t(getPbc().getBox()); - if(getPbc().isOrthorombic()){ - boxfile.printf(" %f %f %f\n",lenunit*t(0,0),lenunit*t(1,1),lenunit*t(2,2)); - }else{ - boxfile.printf(" %f %f %f %f %f %f %f %f %f\n", - lenunit*t(0,0),lenunit*t(0,1),lenunit*t(0,2), - lenunit*t(1,0),lenunit*t(1,1),lenunit*t(1,2), - lenunit*t(2,0),lenunit*t(2,1),lenunit*t(2,2) - ); - } - boxfile.printf("AR %f %f %f \n",lenunit*origin[0],lenunit*origin[1],lenunit*origin[2]); - Vector ut, vt, wt; - ut = origin + len_bi*bi; - vt = origin + len_cross*cross; - wt = origin + len_perp*perp; - boxfile.printf("AR %f %f %f \n",lenunit*(ut[0]) , lenunit*(ut[1]), lenunit*(ut[2]) ); - boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]) , lenunit*(vt[1]), lenunit*(vt[2]) ); - boxfile.printf("AR %f %f %f \n",lenunit*(wt[0]) , lenunit*(wt[1]), lenunit*(wt[2]) ); - boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]+len_bi*bi[0]), - lenunit*(vt[1]+len_bi*bi[1]), - lenunit*(vt[2]+len_bi*bi[2]) ); - boxfile.printf("AR %f %f %f \n",lenunit*(ut[0]+len_perp*perp[0]), - lenunit*(ut[1]+len_perp*perp[1]), - lenunit*(ut[2]+len_perp*perp[2]) ); - boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]+len_perp*perp[0]), - lenunit*(vt[1]+len_perp*perp[1]), - lenunit*(vt[2]+len_perp*perp[2]) ); - boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]+len_perp*perp[0]+len_bi*bi[0]), - lenunit*(vt[1]+len_perp*perp[1]+len_bi*bi[1]), - lenunit*(vt[2]+len_perp*perp[2]+len_bi*bi[2]) ); +void VolumeCavity::update() { + if(boxout) { + boxfile.printf("%d\n",8); + const Tensor & t(getPbc().getBox()); + if(getPbc().isOrthorombic()) { + boxfile.printf(" %f %f %f\n",lenunit*t(0,0),lenunit*t(1,1),lenunit*t(2,2)); + } else { + boxfile.printf(" %f %f %f %f %f %f %f %f %f\n", + lenunit*t(0,0),lenunit*t(0,1),lenunit*t(0,2), + lenunit*t(1,0),lenunit*t(1,1),lenunit*t(1,2), + lenunit*t(2,0),lenunit*t(2,1),lenunit*t(2,2) + ); + } + boxfile.printf("AR %f %f %f \n",lenunit*origin[0],lenunit*origin[1],lenunit*origin[2]); + Vector ut, vt, wt; + ut = origin + len_bi*bi; + vt = origin + len_cross*cross; + wt = origin + len_perp*perp; + boxfile.printf("AR %f %f %f \n",lenunit*(ut[0]), lenunit*(ut[1]), lenunit*(ut[2]) ); + boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]), lenunit*(vt[1]), lenunit*(vt[2]) ); + boxfile.printf("AR %f %f %f \n",lenunit*(wt[0]), lenunit*(wt[1]), lenunit*(wt[2]) ); + boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]+len_bi*bi[0]), + lenunit*(vt[1]+len_bi*bi[1]), + lenunit*(vt[2]+len_bi*bi[2]) ); + boxfile.printf("AR %f %f %f \n",lenunit*(ut[0]+len_perp*perp[0]), + lenunit*(ut[1]+len_perp*perp[1]), + lenunit*(ut[2]+len_perp*perp[2]) ); + boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]+len_perp*perp[0]), + lenunit*(vt[1]+len_perp*perp[1]), + lenunit*(vt[2]+len_perp*perp[2]) ); + boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]+len_perp*perp[0]+len_bi*bi[0]), + lenunit*(vt[1]+len_perp*perp[1]+len_bi*bi[1]), + lenunit*(vt[2]+len_perp*perp[2]+len_bi*bi[2]) ); } } @@ -367,8 +367,8 @@ double VolumeCavity::calculateNumberInside( const Vector& cpos, Vector& derivati bead.set( 0, len_bi, sigma ); double upos=dotProduct( datom, bi ); ucontr=bead.calculate( upos, uder ); - double udlen=bead.uboundDerivative( upos ); - double uder2 = bead.lboundDerivative( upos ) - udlen; + double udlen=bead.uboundDerivative( upos ); + double uder2 = bead.lboundDerivative( upos ) - udlen; // Calculate contribution from integral along cross bead.set( 0, len_cross, sigma ); @@ -388,24 +388,24 @@ double VolumeCavity::calculateNumberInside( const Vector& cpos, Vector& derivati derivatives[0] = (dfd[0]*bi[0]+dfd[1]*cross[0]+dfd[2]*perp[0]); derivatives[1] = (dfd[0]*bi[1]+dfd[1]*cross[1]+dfd[2]*perp[1]); derivatives[2] = (dfd[0]*bi[2]+dfd[1]*cross[2]+dfd[2]*perp[2]); - double tot = ucontr*vcontr*wcontr*jacob_det; + double tot = ucontr*vcontr*wcontr*jacob_det; // Add reference atom derivatives dfd[0]=uder2*vcontr*wcontr; dfd[1]=ucontr*vder2*wcontr; dfd[2]=ucontr*vcontr*wder2; Vector dfld; dfld[0]=udlen*vcontr*wcontr; dfld[1]=ucontr*vdlen*wcontr; dfld[2]=ucontr*vcontr*wdlen; rderiv[0] = dfd[0]*matmul(datom,dbi[0]) + dfd[1]*matmul(datom,dcross[0]) + dfd[2]*matmul(datom,dperp[0]) + - dfld[0]*dlbi[0] + dfld[1]*dlcross[0] + dfld[2]*dlperp[0] - derivatives; - rderiv[1] = dfd[0]*matmul(datom,dbi[1]) + dfd[1]*matmul(datom,dcross[1]) + dfd[2]*matmul(datom,dperp[1]) + + dfld[0]*dlbi[0] + dfld[1]*dlcross[0] + dfld[2]*dlperp[0] - derivatives; + rderiv[1] = dfd[0]*matmul(datom,dbi[1]) + dfd[1]*matmul(datom,dcross[1]) + dfd[2]*matmul(datom,dperp[1]) + dfld[0]*dlbi[1] + dfld[1]*dlcross[1] + dfld[2]*dlperp[1]; - rderiv[2] = dfd[0]*matmul(datom,dbi[2]) + dfd[1]*matmul(datom,dcross[2]) + dfd[2]*matmul(datom,dperp[2]) + + rderiv[2] = dfd[0]*matmul(datom,dbi[2]) + dfd[1]*matmul(datom,dcross[2]) + dfd[2]*matmul(datom,dperp[2]) + dfld[0]*dlbi[2] + dfld[1]*dlcross[2] + dfld[2]*dlperp[2]; rderiv[3] = dfld[0]*dlbi[3] + dfld[1]*dlcross[3] + dfld[2]*dlperp[3]; vir.zero(); vir-=Tensor( cpos,derivatives ); - for(unsigned i=0;i<4;++i){ - vir -= Tensor( getPosition(i), rderiv[i] ); + for(unsigned i=0; i<4; ++i) { + vir -= Tensor( getPosition(i), rderiv[i] ); } - + return tot; } diff --git a/src/multicolvar/VolumeGradientBase.cpp b/src/multicolvar/VolumeGradientBase.cpp index ffbda80d6..db1b48f6a 100644 --- a/src/multicolvar/VolumeGradientBase.cpp +++ b/src/multicolvar/VolumeGradientBase.cpp @@ -27,121 +27,121 @@ namespace PLMD { namespace multicolvar { -void VolumeGradientBase::registerKeywords( Keywords& keys ){ +void VolumeGradientBase::registerKeywords( Keywords& keys ) { BridgedMultiColvarFunction::registerKeywords( keys ); } VolumeGradientBase::VolumeGradientBase(const ActionOptions&ao): -Action(ao), -BridgedMultiColvarFunction(ao) + Action(ao), + BridgedMultiColvarFunction(ao) { } -void VolumeGradientBase::requestAtoms( const std::vector<AtomNumber>& atoms ){ +void VolumeGradientBase::requestAtoms( const std::vector<AtomNumber>& atoms ) { ActionAtomistic::requestAtoms(atoms); bridgeVariable=3*atoms.size(); - std::map<std::string,bool> checklabs; - for(const auto & p : getDependencies() ) checklabs.insert(std::pair<std::string,bool>(p->getLabel(),false)); - for(const auto & p : plumed.getActionSet() ){ - if( p->getLabel()==getPntrToMultiColvar()->getLabel() ) break; - if( checklabs.count(p->getLabel()) ) checklabs[p->getLabel()]=true; + std::map<std::string,bool> checklabs; + for(const auto & p : getDependencies() ) checklabs.insert(std::pair<std::string,bool>(p->getLabel(),false)); + for(const auto & p : plumed.getActionSet() ) { + if( p->getLabel()==getPntrToMultiColvar()->getLabel() ) break; + if( checklabs.count(p->getLabel()) ) checklabs[p->getLabel()]=true; } - for(const auto & p : checklabs ){ - if( !p.second ) error("the input for the virtual atoms used in the input for this action must appear in the input file before the input multicolvar"); + for(const auto & p : checklabs ) { + if( !p.second ) error("the input for the virtual atoms used in the input for this action must appear in the input file before the input multicolvar"); } - addDependency( getPntrToMultiColvar() ); + addDependency( getPntrToMultiColvar() ); tmpforces.resize( 3*atoms.size()+9 ); } -void VolumeGradientBase::doJobsRequiredBeforeTaskList(){ +void VolumeGradientBase::doJobsRequiredBeforeTaskList() { ActionWithValue::clearDerivatives(); retrieveAtoms(); setupRegions(); ActionWithVessel::doJobsRequiredBeforeTaskList(); } void VolumeGradientBase::completeTask( const unsigned& curr, MultiValue& invals, MultiValue& outvals ) const { - if( getPntrToMultiColvar()->isDensity() ){ - outvals.setValue(0, 1.0); outvals.setValue(1, 1.0); + if( getPntrToMultiColvar()->isDensity() ) { + outvals.setValue(0, 1.0); outvals.setValue(1, 1.0); } else { - // Copy derivatives of the colvar and the value of the colvar - invals.copyValues( outvals ); - if( derivativesAreRequired() ) invals.copyDerivatives( outvals ); + // Copy derivatives of the colvar and the value of the colvar + invals.copyValues( outvals ); + if( derivativesAreRequired() ) invals.copyDerivatives( outvals ); } - calculateAllVolumes( curr, outvals ); + calculateAllVolumes( curr, outvals ); } -void VolumeGradientBase::setNumberInVolume( const unsigned& ivol, const unsigned& curr, const double& weight, - const Vector& wdf, const Tensor& virial, const std::vector<Vector>& refders, - MultiValue& outvals ) const { - MultiColvarBase* mcolv=getPntrToMultiColvar(); - if( !mcolv->weightHasDerivatives ){ - outvals.setValue(ivol, weight ); - if( derivativesAreRequired() ){ - CatomPack catom; mcolv->getCentralAtomPack( 0, curr, catom ); - for(unsigned i=0;i<catom.getNumberOfAtomsWithDerivatives();++i){ - unsigned jatom=3*catom.getIndex(i); - outvals.addDerivative( ivol, jatom+0, catom.getDerivative(i,0,wdf) ); - outvals.addDerivative( ivol, jatom+1, catom.getDerivative(i,1,wdf) ); - outvals.addDerivative( ivol, jatom+2, catom.getDerivative(i,2,wdf) ); - } - unsigned nmder=getPntrToMultiColvar()->getNumberOfDerivatives(); - for(unsigned i=0;i<3;++i) for(unsigned j=0;j<3;++j) outvals.addDerivative( ivol, nmder-9+3*i+j, virial(i,j) ); - for(unsigned i=0;i<refders.size();++i){ - unsigned iatom=nmder+3*i; - - outvals.addDerivative( ivol, iatom+0, refders[i][0] ); - outvals.addDerivative( ivol, iatom+1, refders[i][1] ); - outvals.addDerivative( ivol, iatom+2, refders[i][2] ); - } +void VolumeGradientBase::setNumberInVolume( const unsigned& ivol, const unsigned& curr, const double& weight, + const Vector& wdf, const Tensor& virial, const std::vector<Vector>& refders, + MultiValue& outvals ) const { + MultiColvarBase* mcolv=getPntrToMultiColvar(); + if( !mcolv->weightHasDerivatives ) { + outvals.setValue(ivol, weight ); + if( derivativesAreRequired() ) { + CatomPack catom; mcolv->getCentralAtomPack( 0, curr, catom ); + for(unsigned i=0; i<catom.getNumberOfAtomsWithDerivatives(); ++i) { + unsigned jatom=3*catom.getIndex(i); + outvals.addDerivative( ivol, jatom+0, catom.getDerivative(i,0,wdf) ); + outvals.addDerivative( ivol, jatom+1, catom.getDerivative(i,1,wdf) ); + outvals.addDerivative( ivol, jatom+2, catom.getDerivative(i,2,wdf) ); } - } else if(ivol==0){ - double ww=outvals.get(0); outvals.setValue(ivol,ww*weight); - if( derivativesAreRequired() ){ - plumed_merror("This needs testing"); - CatomPack catom; mcolv->getCentralAtomPack( 0, curr, catom ); - for(unsigned i=0;i<catom.getNumberOfAtomsWithDerivatives();++i){ - unsigned jatom=3*catom.getIndex(i); - outvals.addDerivative( ivol, jatom+0, weight*outvals.getDerivative(ivol,jatom+0) + ww*catom.getDerivative(i,0,wdf) ); - outvals.addDerivative( ivol, jatom+1, weight*outvals.getDerivative(ivol,jatom+1) + ww*catom.getDerivative(i,1,wdf) ); - outvals.addDerivative( ivol, jatom+2, weight*outvals.getDerivative(ivol,jatom+2) + ww*catom.getDerivative(i,2,wdf) ); - } - unsigned nmder=getPntrToMultiColvar()->getNumberOfDerivatives(); - for(unsigned i=0;i<3;++i) for(unsigned j=0;j<3;++j) outvals.addDerivative( ivol, nmder-9+3*i+j, ww*virial(i,j) ); - for(unsigned i=0;i<refders.size();++i){ - unsigned iatom=nmder+3*i; - outvals.addDerivative( ivol, iatom+0, ww*refders[i][0] ); - outvals.addDerivative( ivol, iatom+1, ww*refders[i][1] ); - outvals.addDerivative( ivol, iatom+2, ww*refders[i][2] ); - } + unsigned nmder=getPntrToMultiColvar()->getNumberOfDerivatives(); + for(unsigned i=0; i<3; ++i) for(unsigned j=0; j<3; ++j) outvals.addDerivative( ivol, nmder-9+3*i+j, virial(i,j) ); + for(unsigned i=0; i<refders.size(); ++i) { + unsigned iatom=nmder+3*i; + + outvals.addDerivative( ivol, iatom+0, refders[i][0] ); + outvals.addDerivative( ivol, iatom+1, refders[i][1] ); + outvals.addDerivative( ivol, iatom+2, refders[i][2] ); + } + } + } else if(ivol==0) { + double ww=outvals.get(0); outvals.setValue(ivol,ww*weight); + if( derivativesAreRequired() ) { + plumed_merror("This needs testing"); + CatomPack catom; mcolv->getCentralAtomPack( 0, curr, catom ); + for(unsigned i=0; i<catom.getNumberOfAtomsWithDerivatives(); ++i) { + unsigned jatom=3*catom.getIndex(i); + outvals.addDerivative( ivol, jatom+0, weight*outvals.getDerivative(ivol,jatom+0) + ww*catom.getDerivative(i,0,wdf) ); + outvals.addDerivative( ivol, jatom+1, weight*outvals.getDerivative(ivol,jatom+1) + ww*catom.getDerivative(i,1,wdf) ); + outvals.addDerivative( ivol, jatom+2, weight*outvals.getDerivative(ivol,jatom+2) + ww*catom.getDerivative(i,2,wdf) ); } + unsigned nmder=getPntrToMultiColvar()->getNumberOfDerivatives(); + for(unsigned i=0; i<3; ++i) for(unsigned j=0; j<3; ++j) outvals.addDerivative( ivol, nmder-9+3*i+j, ww*virial(i,j) ); + for(unsigned i=0; i<refders.size(); ++i) { + unsigned iatom=nmder+3*i; + outvals.addDerivative( ivol, iatom+0, ww*refders[i][0] ); + outvals.addDerivative( ivol, iatom+1, ww*refders[i][1] ); + outvals.addDerivative( ivol, iatom+2, ww*refders[i][2] ); + } + } } else { - double ww=outvals.get(0); outvals.setValue(ivol,ww*weight); - if( derivativesAreRequired() ){ - plumed_merror("This needs testing"); - CatomPack catom; mcolv->getCentralAtomPack( 0, curr, catom ); - for(unsigned i=0;i<catom.getNumberOfAtomsWithDerivatives();++i){ - unsigned jatom=3*catom.getIndex(i); - outvals.addDerivative( ivol, jatom+0, ww*catom.getDerivative(i,0,wdf) ); - outvals.addDerivative( ivol, jatom+1, ww*catom.getDerivative(i,1,wdf) ); - outvals.addDerivative( ivol, jatom+2, ww*catom.getDerivative(i,2,wdf) ); - } - unsigned nmder=getPntrToMultiColvar()->getNumberOfDerivatives(); - for(unsigned i=0;i<3;++i) for(unsigned j=0;j<3;++j) outvals.addDerivative( ivol, nmder-9+3*i+j, ww*virial(i,j) ); - for(unsigned i=0;i<refders.size();++i){ - unsigned iatom=nmder+3*i; - outvals.addDerivative( ivol, iatom+0, ww*refders[i][0] ); - outvals.addDerivative( ivol, iatom+1, ww*refders[i][1] ); - outvals.addDerivative( ivol, iatom+2, ww*refders[i][2] ); - } + double ww=outvals.get(0); outvals.setValue(ivol,ww*weight); + if( derivativesAreRequired() ) { + plumed_merror("This needs testing"); + CatomPack catom; mcolv->getCentralAtomPack( 0, curr, catom ); + for(unsigned i=0; i<catom.getNumberOfAtomsWithDerivatives(); ++i) { + unsigned jatom=3*catom.getIndex(i); + outvals.addDerivative( ivol, jatom+0, ww*catom.getDerivative(i,0,wdf) ); + outvals.addDerivative( ivol, jatom+1, ww*catom.getDerivative(i,1,wdf) ); + outvals.addDerivative( ivol, jatom+2, ww*catom.getDerivative(i,2,wdf) ); + } + unsigned nmder=getPntrToMultiColvar()->getNumberOfDerivatives(); + for(unsigned i=0; i<3; ++i) for(unsigned j=0; j<3; ++j) outvals.addDerivative( ivol, nmder-9+3*i+j, ww*virial(i,j) ); + for(unsigned i=0; i<refders.size(); ++i) { + unsigned iatom=nmder+3*i; + outvals.addDerivative( ivol, iatom+0, ww*refders[i][0] ); + outvals.addDerivative( ivol, iatom+1, ww*refders[i][1] ); + outvals.addDerivative( ivol, iatom+2, ww*refders[i][2] ); } + } } } -void VolumeGradientBase::addBridgeForces( const std::vector<double>& bb ){ +void VolumeGradientBase::addBridgeForces( const std::vector<double>& bb ) { plumed_dbg_assert( bb.size()==tmpforces.size()-9 ); // Forces on local atoms - for(unsigned i=0;i<bb.size();++i) tmpforces[i]=bb[i]; + for(unsigned i=0; i<bb.size(); ++i) tmpforces[i]=bb[i]; // Virial contribution is zero - for(unsigned i=bb.size();i<bb.size()+9;++i) tmpforces[i]=0.0; + for(unsigned i=bb.size(); i<bb.size()+9; ++i) tmpforces[i]=0.0; setForcesOnAtoms( tmpforces, 0 ); } diff --git a/src/multicolvar/VolumeGradientBase.h b/src/multicolvar/VolumeGradientBase.h index 0741a917b..31cb5332f 100644 --- a/src/multicolvar/VolumeGradientBase.h +++ b/src/multicolvar/VolumeGradientBase.h @@ -28,7 +28,7 @@ namespace PLMD { namespace multicolvar { class VolumeGradientBase : public BridgedMultiColvarFunction { -friend class MultiColvarBase; + friend class MultiColvarBase; private: /// This is used to store forces temporarily in apply std::vector<double> tmpforces; @@ -41,10 +41,10 @@ protected: Vector pbcDistance( const Vector& v1, const Vector& v2) const; /// Get position of atom Vector getPosition( int iatom ) const ; -/// Request the atoms +/// Request the atoms void requestAtoms( const std::vector<AtomNumber>& atoms ); /// Set the number in the volume - void setNumberInVolume( const unsigned& , const unsigned& , const double& , const Vector& , const Tensor& , const std::vector<Vector>& , MultiValue& ) const ; + void setNumberInVolume( const unsigned&, const unsigned&, const double&, const Vector&, const Tensor&, const std::vector<Vector>&, MultiValue& ) const ; public: static void registerKeywords( Keywords& keys ); explicit VolumeGradientBase(const ActionOptions&); @@ -54,40 +54,40 @@ public: void completeTask( const unsigned& curr, MultiValue& invals, MultiValue& outvals ) const ; /// Calculate what is in the volumes virtual void calculateAllVolumes( const unsigned& curr, MultiValue& outvals ) const=0; -/// Setup the regions that this is based on +/// Setup the regions that this is based on virtual void setupRegions()=0; /// Forces here are applied through the bridge void addBridgeForces( const std::vector<double>& bb ); }; inline -const Tensor & VolumeGradientBase::getBox()const{ +const Tensor & VolumeGradientBase::getBox()const { return getPntrToMultiColvar()->getBox(); -} +} inline const Pbc & VolumeGradientBase::getPbc() const { - return getPntrToMultiColvar()->getPbc(); + return getPntrToMultiColvar()->getPbc(); } inline Vector VolumeGradientBase::pbcDistance( const Vector& v1, const Vector& v2) const { - return getPntrToMultiColvar()->pbcDistance(v1,v2); + return getPntrToMultiColvar()->pbcDistance(v1,v2); } inline Vector VolumeGradientBase::getPosition( int iatom ) const { - if( !checkNumericalDerivatives() ) return ActionAtomistic::getPosition(iatom); - // This is for numerical derivatives of quantity wrt to the local atoms - Vector tmp_p = ActionAtomistic::getPosition(iatom); - if( bridgeVariable<3*getNumberOfAtoms() ){ + if( !checkNumericalDerivatives() ) return ActionAtomistic::getPosition(iatom); +// This is for numerical derivatives of quantity wrt to the local atoms + Vector tmp_p = ActionAtomistic::getPosition(iatom); + if( bridgeVariable<3*getNumberOfAtoms() ) { if( bridgeVariable>=3*iatom && bridgeVariable<(iatom+1)*3 ) tmp_p[bridgeVariable%3]+=sqrt(epsilon); - } - // This makes sure that numerical derivatives of virial are calculated correctly - tmp_p = ActionAtomistic::getPbc().realToScaled( tmp_p ); - tmp_p = getPbc().scaledToReal( tmp_p ); - return tmp_p; -} + } +// This makes sure that numerical derivatives of virial are calculated correctly + tmp_p = ActionAtomistic::getPbc().realToScaled( tmp_p ); + tmp_p = getPbc().scaledToReal( tmp_p ); + return tmp_p; +} } } diff --git a/src/multicolvar/VolumeInCylinder.cpp b/src/multicolvar/VolumeInCylinder.cpp index 3008bd156..eb6bc611e 100644 --- a/src/multicolvar/VolumeInCylinder.cpp +++ b/src/multicolvar/VolumeInCylinder.cpp @@ -26,33 +26,33 @@ //+PLUMEDOC VOLUMES INCYLINDER /* -This quantity can be used to calculate functions of the distribution of collective +This quantity can be used to calculate functions of the distribution of collective variables for the atoms that lie in a particular, user-specified part of of the cell. -Each of the base quantities calculated by a multicolvar can can be assigned to a particular point in three +Each of the base quantities calculated by a multicolvar can can be assigned to a particular point in three dimensional space. For example, if we have the coordination numbers for all the atoms in the -system each coordination number can be assumed to lie on the position of the central atom. +system each coordination number can be assumed to lie on the position of the central atom. Because each base quantity can be assigned to a particular point in space we can calculate functions of the distribution of base quantities in a particular part of the box by using: \f[ -\overline{s}_{\tau} = \frac{ \sum_i f(s_i) \sigma(r_{xy}) }{ \sum_i \sigma(r_{xy}) } -\f] +\overline{s}_{\tau} = \frac{ \sum_i f(s_i) \sigma(r_{xy}) }{ \sum_i \sigma(r_{xy}) } +\f] where the sum is over the collective variables, \f$s_i\f$, each of which can be thought to be at \f$ (x_i,y_i,z_i)\f$. -The function \f$\sigma\f$ is a \ref switchingfunction that acts on the distance between the point at which the -collective is located \f$(x_i,y_i,z_i)\f$ and the position of the atom that was specified using the ORIGIN keyword +The function \f$\sigma\f$ is a \ref switchingfunction that acts on the distance between the point at which the +collective is located \f$(x_i,y_i,z_i)\f$ and the position of the atom that was specified using the ORIGIN keyword projected in the xy plane if DIRECTION=z is used. In other words: \f[ r_{xy} = sqrt{ ( x_i - x_0)^2 + ( y_i - y_0)^2 } \f] -In short this function, \f$\sigma(r_{xy})\f$, measures whether or not the CV is within a cylinder that +In short this function, \f$\sigma(r_{xy})\f$, measures whether or not the CV is within a cylinder that runs along the axis specified using the DIRECTION keyword and that is centered on the position of the atom specified using ORIGIN. The function \f$(s_i)\f$ can be any of the usual LESS_THAN, MORE_THAN, WITHIN etc that are used in all other multicolvars. -When INCYLINDER is used with the \ref DENSITY action the number of atoms in the specified region is calculated +When INCYLINDER is used with the \ref DENSITY action the number of atoms in the specified region is calculated \par Examples @@ -60,7 +60,7 @@ The input below can be use to calculate the average coordination numbers for tho of radius 1.5 nm that is centered on the position of atom 101 and that has its long axis parallel to the z-axis. \verbatim -c1: COORDINATIONNUMBER SPECIES=1-100 SWITCH={RATIONAL R_0=0.1} +c1: COORDINATIONNUMBER SPECIES=1-100 SWITCH={RATIONAL R_0=0.1} d2: INCYLINDER ATOM=101 DATA=d1 DIRECTION=Z RADIUS={TANH R_0=1.5} SIGMA=0.1 LOWER=-0.1 UPPER=0.1 MEAN PRINT ARG=d2.* FILE=colvar \endverbatim @@ -76,18 +76,18 @@ private: bool docylinder; Vector origin; HistogramBead bead; - std::vector<unsigned> dir; + std::vector<unsigned> dir; SwitchingFunction switchingFunction; public: static void registerKeywords( Keywords& keys ); explicit VolumeInCylinder (const ActionOptions& ao); void setupRegions(); double calculateNumberInside( const Vector& cpos, Vector& derivatives, Tensor& vir, std::vector<Vector>& refders ) const ; -}; +}; PLUMED_REGISTER_ACTION(VolumeInCylinder,"INCYLINDER") -void VolumeInCylinder::registerKeywords( Keywords& keys ){ +void VolumeInCylinder::registerKeywords( Keywords& keys ) { ActionVolume::registerKeywords( keys ); keys.add("atoms","ATOM","the atom whose vicinity we are interested in examining"); keys.add("compulsory","DIRECTION","the direction of the long axis of the cylinder. Must be x, y or z"); @@ -98,21 +98,21 @@ void VolumeInCylinder::registerKeywords( Keywords& keys ){ } VolumeInCylinder::VolumeInCylinder(const ActionOptions& ao): -Action(ao), -ActionVolume(ao), -docylinder(false) + Action(ao), + ActionVolume(ao), + docylinder(false) { - std::vector<AtomNumber> atom; + std::vector<AtomNumber> atom; parseAtomList("ATOM",atom); if( atom.size()!=1 ) error("should only be one atom specified"); log.printf(" center of cylinder is at position of atom : %d\n",atom[0].serial() ); std::string sdir; parse("DIRECTION",sdir); - if( sdir=="X"){dir.push_back(1); dir.push_back(2); dir.push_back(0); } - else if( sdir=="Y"){dir.push_back(0); dir.push_back(2); dir.push_back(1); } - else if( sdir=="Z"){dir.push_back(0); dir.push_back(1); dir.push_back(2); } + if( sdir=="X") {dir.push_back(1); dir.push_back(2); dir.push_back(0); } + else if( sdir=="Y") {dir.push_back(0); dir.push_back(2); dir.push_back(1); } + else if( sdir=="Z") {dir.push_back(0); dir.push_back(1); dir.push_back(2); } else { error(sdir + "is not a valid direction. Should be X, Y or Z"); } - log.printf(" cylinder's long axis is along %s axis\n",sdir.c_str() ); + log.printf(" cylinder's long axis is along %s axis\n",sdir.c_str() ); std::string sw, errors; parse("RADIUS",sw); if(sw.length()==0) error("missing RADIUS keyword"); @@ -121,33 +121,33 @@ docylinder(false) log.printf(" radius of cylinder is given by %s \n", ( switchingFunction.description() ).c_str() ); double min, max; parse("LOWER",min); parse("UPPER",max); - if( min!=0.0 || max!=0.0 ){ - if( min>max ) error("minimum of cylinder should be less than maximum"); - docylinder=true; - log.printf(" cylinder extends from %f to %f along the %s axis\n",min,max,sdir.c_str() ); - bead.isNotPeriodic(); bead.setKernelType( getKernelType() ); bead.set( min, max, getSigma() ); + if( min!=0.0 || max!=0.0 ) { + if( min>max ) error("minimum of cylinder should be less than maximum"); + docylinder=true; + log.printf(" cylinder extends from %f to %f along the %s axis\n",min,max,sdir.c_str() ); + bead.isNotPeriodic(); bead.setKernelType( getKernelType() ); bead.set( min, max, getSigma() ); } - checkRead(); requestAtoms(atom); + checkRead(); requestAtoms(atom); } -void VolumeInCylinder::setupRegions(){ } +void VolumeInCylinder::setupRegions() { } double VolumeInCylinder::calculateNumberInside( const Vector& cpos, Vector& derivatives, Tensor& vir, std::vector<Vector>& refders ) const { // Calculate position of atom wrt to origin Vector fpos=pbcDistance( getPosition(0), cpos ); - + double vcylinder, dcylinder; - if( docylinder ){ - vcylinder=bead.calculate( fpos[dir[2]], dcylinder ); + if( docylinder ) { + vcylinder=bead.calculate( fpos[dir[2]], dcylinder ); } else { - vcylinder=1.0; dcylinder=0.0; + vcylinder=1.0; dcylinder=0.0; } const double dd = fpos[dir[0]]*fpos[dir[0]] + fpos[dir[1]]*fpos[dir[1]]; double dfunc, vswitch = switchingFunction.calculateSqr( dd, dfunc ); derivatives.zero(); double value=vswitch*vcylinder; - derivatives[dir[0]]=vcylinder*dfunc*fpos[dir[0]]; + derivatives[dir[0]]=vcylinder*dfunc*fpos[dir[0]]; derivatives[dir[1]]=vcylinder*dfunc*fpos[dir[1]]; derivatives[dir[2]]=vswitch*dcylinder; // Add derivatives wrt to position of origin atom diff --git a/src/multicolvar/VolumeInSphere.cpp b/src/multicolvar/VolumeInSphere.cpp index 61badf5f3..632af88df 100644 --- a/src/multicolvar/VolumeInSphere.cpp +++ b/src/multicolvar/VolumeInSphere.cpp @@ -26,40 +26,40 @@ //+PLUMEDOC VOLUMES INSPHERE /* -This quantity can be used to calculate functions of the distribution of collective +This quantity can be used to calculate functions of the distribution of collective variables for the atoms that lie in a particular, user-specified part of of the cell. -Each of the base quantities calculated by a multicolvar can can be assigned to a particular point in three +Each of the base quantities calculated by a multicolvar can can be assigned to a particular point in three dimensional space. For example, if we have the coordination numbers for all the atoms in the -system each coordination number can be assumed to lie on the position of the central atom. +system each coordination number can be assumed to lie on the position of the central atom. Because each base quantity can be assigned to a particular point in space we can calculate functions of the distribution of base quantities in a particular part of the box by using: \f[ -\overline{s}_{\tau} = \frac{ \sum_i f(s_i) \sigma(r) }{ \sum_i \sigma(r) } -\f] +\overline{s}_{\tau} = \frac{ \sum_i f(s_i) \sigma(r) }{ \sum_i \sigma(r) } +\f] where the sum is over the collective variables, \f$s_i\f$, each of which can be thought to be at \f$ (x_i,y_i,z_i)\f$. -The function \f$\sigma\f$ is a \ref switchingfunction that acts on the distance between the point at which the +The function \f$\sigma\f$ is a \ref switchingfunction that acts on the distance between the point at which the collective is located \f$(x_i,y_i,z_i)\f$ and the position of the atom that was specified using the ORIGIN keyword. In other words: \f[ r = sqrt{ ( x_i - x_0)^2 + ( y_i - y_0)^2 + ( z_i - z_0)^2} -\f] -In short this function, \f$\sigma(r_{xy})\f$, measures whether or not the CV is within a sphere that is +\f] +In short this function, \f$\sigma(r_{xy})\f$, measures whether or not the CV is within a sphere that is centered on the position of the atom specified using the keyword ORIGIN. The function \f$(s_i)\f$ can be any of the usual LESS_THAN, MORE_THAN, WITHIN etc that are used in all other multicolvars. -When INCYLINDER is used with the \ref DENSITY action the number of atoms in the specified region is calculated +When INCYLINDER is used with the \ref DENSITY action the number of atoms in the specified region is calculated \par Examples -The input below can be use to calculate the average coordination numbers for those atoms that are within a sphere +The input below can be use to calculate the average coordination numbers for those atoms that are within a sphere of radius 1.5 nm that is centered on the position of atom 101. \verbatim -c1: COORDINATIONNUMBER SPECIES=1-100 SWITCH={RATIONAL R_0=0.1} +c1: COORDINATIONNUMBER SPECIES=1-100 SWITCH={RATIONAL R_0=0.1} d2: INSPHERE ATOM=101 DATA=d1 RADIUS={TANH R_0=1.5} SIGMA=0.1 LOWER=-0.1 UPPER=0.1 MEAN PRINT ARG=d2.* FILE=colvar \endverbatim @@ -79,11 +79,11 @@ public: explicit VolumeInSphere(const ActionOptions& ao); void setupRegions(); double calculateNumberInside( const Vector& cpos, Vector& derivatives, Tensor& vir, std::vector<Vector>& refders ) const ; -}; +}; PLUMED_REGISTER_ACTION(VolumeInSphere,"INSPHERE") -void VolumeInSphere::registerKeywords( Keywords& keys ){ +void VolumeInSphere::registerKeywords( Keywords& keys ) { ActionVolume::registerKeywords( keys ); keys.add("atoms","ATOM","the atom whose vicinity we are interested in examining"); keys.add("compulsory","RADIUS","the switching function that tells us the extent of the sphereical region of interest"); @@ -91,10 +91,10 @@ void VolumeInSphere::registerKeywords( Keywords& keys ){ } VolumeInSphere::VolumeInSphere(const ActionOptions& ao): -Action(ao), -ActionVolume(ao) + Action(ao), + ActionVolume(ao) { - std::vector<AtomNumber> atom; + std::vector<AtomNumber> atom; parseAtomList("ATOM",atom); if( atom.size()!=1 ) error("should only be one atom specified"); log.printf(" center of sphere is at position of atom : %d\n",atom[0].serial() ); @@ -105,15 +105,15 @@ ActionVolume(ao) if( errors.length()!=0 ) error("problem reading RADIUS keyword : " + errors ); log.printf(" radius of sphere is given by %s \n", ( switchingFunction.description() ).c_str() ); - checkRead(); requestAtoms(atom); + checkRead(); requestAtoms(atom); } -void VolumeInSphere::setupRegions(){ } +void VolumeInSphere::setupRegions() { } double VolumeInSphere::calculateNumberInside( const Vector& cpos, Vector& derivatives, Tensor& vir, std::vector<Vector>& refders ) const { // Calculate position of atom wrt to origin Vector fpos=pbcDistance( getPosition(0), cpos ); - double dfunc, value = switchingFunction.calculateSqr( fpos.modulo2(), dfunc ); + double dfunc, value = switchingFunction.calculateSqr( fpos.modulo2(), dfunc ); derivatives.zero(); derivatives = dfunc*fpos; refders[0] = -derivatives; // Add a virial contribution vir -= Tensor(fpos,derivatives); diff --git a/src/multicolvar/VolumeTetrapore.cpp b/src/multicolvar/VolumeTetrapore.cpp index f2cb668b3..98fe915c3 100644 --- a/src/multicolvar/VolumeTetrapore.cpp +++ b/src/multicolvar/VolumeTetrapore.cpp @@ -26,24 +26,24 @@ #include "tools/Pbc.h" #include "ActionVolume.h" -//+PLUMEDOC VOLUMES TETRAHEDRALPORE +//+PLUMEDOC VOLUMES TETRAHEDRALPORE /* This quantity can be used to calculate functions of the distribution of collective variables for the atoms lie that lie in a box defined by the positions of four atoms at the corners of a tetrahedron. -Each of the base quantities calculated by a multicolvar can can be assigned to a particular point in three +Each of the base quantities calculated by a multicolvar can can be assigned to a particular point in three dimensional space. For example, if we have the coordination numbers for all the atoms in the -system each coordination number can be assumed to lie on the position of the central atom. +system each coordination number can be assumed to lie on the position of the central atom. Because each base quantity can be assigned to a particular point in space we can calculate functions of the distribution of base quantities in a particular part of the box by using: \f[ -\overline{s}_{\tau} = \frac{ \sum_i f(s_i) w(u_i,v_i,w_i) }{ \sum_i w(u_i,v_i,w_i) } -\f] +\overline{s}_{\tau} = \frac{ \sum_i f(s_i) w(u_i,v_i,w_i) }{ \sum_i w(u_i,v_i,w_i) } +\f] where the sum is over the collective variables, \f$s_i\f$, each of which can be thought to be at \f$ (u_i,v_i,z_i)\f$. The function \f$(s_i)\f$ can be any of the usual LESS_THAN, MORE_THAN, WITHIN etc that are used in all other multicolvars. -Notice that here (at variance with what is done in \ref AROUND) we have transformed from the usual \f$(x_i,y_i,z_i)\f$ +Notice that here (at variance with what is done in \ref AROUND) we have transformed from the usual \f$(x_i,y_i,z_i)\f$ position to a position in \f$ (u_i,v_i,z_i)\f$. This is done using a rotation matrix as follows: \f[ @@ -63,10 +63,10 @@ position to a position in \f$ (u_i,v_i,z_i)\f$. This is done using a rotation m \right) \f] -where \f$\mathbf{R}\f$ is a rotation matrix that is calculated by constructing a set of three orthonormal vectors from the -refererence positions specified by the user. Initially unit vectors are found by calculating the bisector, \f$\mathbf{b}\f$, and -cross product, \f$\mathbf{c}\f$, of the vectors connecting atoms 1 and 2. A third unit vector, \f$\mathbf{p}\f$ is then found by taking the cross -product between the cross product calculated during the first step, \f$\mathbf{c}\f$ and the bisector, \f$\mathbf{b}\f$. From this +where \f$\mathbf{R}\f$ is a rotation matrix that is calculated by constructing a set of three orthonormal vectors from the +refererence positions specified by the user. Initially unit vectors are found by calculating the bisector, \f$\mathbf{b}\f$, and +cross product, \f$\mathbf{c}\f$, of the vectors connecting atoms 1 and 2. A third unit vector, \f$\mathbf{p}\f$ is then found by taking the cross +product between the cross product calculated during the first step, \f$\mathbf{c}\f$ and the bisector, \f$\mathbf{b}\f$. From this second cross product \f$\mathbf{p}\f$ and the bisector \f$\mathbf{b}\f$ two new vectors are calculated using: \f[ @@ -78,13 +78,13 @@ In the previous function \f$ w(u_i,v_i,w_i) \f$ measures whether or not the syst is equal to: \f[ -w(u_i,v_i,w_i) = \int_{0}^{u'} \int_{0}^{v'} \int_{0}^{w'} \textrm{d}u\textrm{d}v\textrm{d}w - K\left( \frac{u - u_i}{\sigma} \right)K\left( \frac{v - v_i}{\sigma} \right)K\left( \frac{w - w_i}{\sigma} \right) +w(u_i,v_i,w_i) = \int_{0}^{u'} \int_{0}^{v'} \int_{0}^{w'} \textrm{d}u\textrm{d}v\textrm{d}w + K\left( \frac{u - u_i}{\sigma} \right)K\left( \frac{v - v_i}{\sigma} \right)K\left( \frac{w - w_i}{\sigma} \right) \f] -where \f$K\f$ is one of the kernel functions described on \ref histogrambead and \f$\sigma\f$ is a bandwidth parameter. -The values of \f$u'\f$ and \f$v'\f$ are found by finding the projections of the vectors connecting atoms 1 and 2 and 1 -and 3 \f$v_1\f$ and \f$v_2\f$. This gives four projections: the largest two projections are used in the remainder of +where \f$K\f$ is one of the kernel functions described on \ref histogrambead and \f$\sigma\f$ is a bandwidth parameter. +The values of \f$u'\f$ and \f$v'\f$ are found by finding the projections of the vectors connecting atoms 1 and 2 and 1 +and 3 \f$v_1\f$ and \f$v_2\f$. This gives four projections: the largest two projections are used in the remainder of the calculations. \f$w'\f$ is calculated by taking the projection of the vector connecting atoms 1 and 4 on the vector \f$\mathbf{c}\f$. Notice that the manner by which this box is constructed differs from the way this is done in \ref CAVITY. This is in fact the only point of difference between these two actions. @@ -95,11 +95,11 @@ The following commands tell plumed to calculate the number of atom inside a tetr cavity is calculated from the positions of atoms 1, 4, 5, and 11, The final value will be labeled cav. \verbatim -d1: DENSITY SPECIES=20-500 +d1: DENSITY SPECIES=20-500 TETRAHEDRALPORE DATA=d1 ATOMS=1,4,5,11 SIGMA=0.1 LABEL=cav \endverbatim -The following command tells plumed to calculate the coordination numbers (with other water molecules) for the water +The following command tells plumed to calculate the coordination numbers (with other water molecules) for the water molecules in the tetrahedral cavity described above. The average coordination number and the number of coordination numbers more than 4 is then calculated. The values of these two quantities are given the labels cav.mean and cav.morethan @@ -135,7 +135,7 @@ public: PLUMED_REGISTER_ACTION(VolumeTetrapore,"TETRAHEDRALPORE") -void VolumeTetrapore::registerKeywords( Keywords& keys ){ +void VolumeTetrapore::registerKeywords( Keywords& keys ) { ActionVolume::registerKeywords( keys ); keys.add("atoms","ATOMS","the positions of four atoms that define spatial extent of the cavity"); keys.addFlag("PRINT_BOX",false,"write out the positions of the corners of the box to an xyz file"); @@ -144,54 +144,54 @@ void VolumeTetrapore::registerKeywords( Keywords& keys ){ } VolumeTetrapore::VolumeTetrapore(const ActionOptions& ao): -Action(ao), -ActionVolume(ao), -boxout(false), -lenunit(1.0), -dlbi(4), -dlcross(4), -dlperp(4), -dbi(3), -dcross(3), -dperp(3) + Action(ao), + ActionVolume(ao), + boxout(false), + lenunit(1.0), + dlbi(4), + dlcross(4), + dlperp(4), + dbi(3), + dcross(3), + dperp(3) { std::vector<AtomNumber> atoms; parseAtomList("ATOMS",atoms); if( atoms.size()!=4 ) error("number of atoms should be equal to four"); log.printf(" boundaries for region are calculated based on positions of atoms : "); - for(unsigned i=0;i<atoms.size();++i) log.printf("%d ",atoms[i].serial() ); + for(unsigned i=0; i<atoms.size(); ++i) log.printf("%d ",atoms[i].serial() ); log.printf("\n"); boxout=false; parseFlag("PRINT_BOX",boxout); - if(boxout){ - std::string boxfname; parse("FILE",boxfname); - if(boxfname.length()==0) error("no name for box file specified"); - std::string unitname; parse("UNITS",unitname); - if ( unitname.length()>0 ){ - Units u; u.setLength(unitname); - lenunit=plumed.getAtoms().getUnits().getLength()/u.getLength(); - } else { - unitname="nm"; - } - boxfile.link(*this); - boxfile.open( boxfname.c_str() ); - log.printf(" printing box coordinates on file named %s in %s \n",boxfname.c_str(), unitname.c_str() ); - } + if(boxout) { + std::string boxfname; parse("FILE",boxfname); + if(boxfname.length()==0) error("no name for box file specified"); + std::string unitname; parse("UNITS",unitname); + if ( unitname.length()>0 ) { + Units u; u.setLength(unitname); + lenunit=plumed.getAtoms().getUnits().getLength()/u.getLength(); + } else { + unitname="nm"; + } + boxfile.link(*this); + boxfile.open( boxfname.c_str() ); + log.printf(" printing box coordinates on file named %s in %s \n",boxfname.c_str(), unitname.c_str() ); + } checkRead(); requestAtoms(atoms); // We have to readd the dependency because requestAtoms removes it - addDependency( getPntrToMultiColvar() ); + addDependency( getPntrToMultiColvar() ); } -VolumeTetrapore::~VolumeTetrapore(){ +VolumeTetrapore::~VolumeTetrapore() { } -void VolumeTetrapore::setupRegions(){ +void VolumeTetrapore::setupRegions() { // Make some space for things Vector d1, d2, d3; - + // Retrieve the sigma value sigma=getSigma(); // Set the position of the origin @@ -201,7 +201,7 @@ void VolumeTetrapore::setupRegions(){ d1 = pbcDistance(origin,getPosition(1)); d2 = pbcDistance(origin,getPosition(2)); - // Find the vector connecting the origin to the top corner of + // Find the vector connecting the origin to the top corner of // the subregion d3 = pbcDistance(origin,getPosition(3)); @@ -209,19 +209,19 @@ void VolumeTetrapore::setupRegions(){ Vector bisector = d1 + d2; double bmod=bisector.modulo(); bisector=bisector/bmod; // bi = d1 / d1l; len_bi=dotProduct( d3, bi ); - cross = crossProduct( d1, d2 ); double crossmod=cross.modulo(); + cross = crossProduct( d1, d2 ); double crossmod=cross.modulo(); cross = cross / crossmod; len_cross=dotProduct( d3, cross ); - Vector truep = crossProduct( cross, bisector ); + Vector truep = crossProduct( cross, bisector ); // These are our true vectors 45 degrees from bisector bi = cos(pi/4.0)*bisector + sin(pi/4.0)*truep; - perp = cos(pi/4.0)*bisector - sin(pi/4.0)*truep; + perp = cos(pi/4.0)*bisector - sin(pi/4.0)*truep; // And the lengths of the various parts average distance to opposite corners of tetetrahedron len_bi = dotProduct( d1, bi ); double len_bi2 = dotProduct( d2, bi ); unsigned lbi=1; - if( len_bi2>len_bi ){ len_bi=len_bi2; lbi=2; } + if( len_bi2>len_bi ) { len_bi=len_bi2; lbi=2; } len_perp = dotProduct( d1, perp ); double len_perp2 = dotProduct( d2, perp ); unsigned lpi=1; - if( len_perp2>len_perp ){ len_perp=len_perp2; lpi=2; } + if( len_perp2>len_perp ) { len_perp=len_perp2; lpi=2; } plumed_assert( lbi!=lpi ); Tensor tcderiv; double cmod3=crossmod*crossmod*crossmod; Vector ucross=crossmod*cross; @@ -230,7 +230,7 @@ void VolumeTetrapore::setupRegions(){ tcderiv.setCol( 2, crossProduct( d1, Vector(0.0,0.0,-1.0) ) + crossProduct( Vector(0.0,0.0,-1.0), d2 ) ); dcross[0](0,0)=( tcderiv(0,0)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 ); // dx/dx dcross[0](0,1)=( tcderiv(0,1)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 ); // dx/dy - dcross[0](0,2)=( tcderiv(0,2)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 ); // dx/dz + dcross[0](0,2)=( tcderiv(0,2)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 ); // dx/dz dcross[0](1,0)=( tcderiv(1,0)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 ); // dy/dx dcross[0](1,1)=( tcderiv(1,1)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 ); // dy/dy dcross[0](1,2)=( tcderiv(1,2)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 ); // dy/dz @@ -243,7 +243,7 @@ void VolumeTetrapore::setupRegions(){ tcderiv.setCol( 2, crossProduct( Vector(0.0,0.0,1.0), d2 ) ); dcross[1](0,0)=( tcderiv(0,0)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 ); // dx/dx dcross[1](0,1)=( tcderiv(0,1)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 ); // dx/dy - dcross[1](0,2)=( tcderiv(0,2)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 ); // dx/dz + dcross[1](0,2)=( tcderiv(0,2)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 ); // dx/dz dcross[1](1,0)=( tcderiv(1,0)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 ); // dy/dx dcross[1](1,1)=( tcderiv(1,1)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 ); // dy/dy dcross[1](1,2)=( tcderiv(1,2)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 ); // dy/dz @@ -256,7 +256,7 @@ void VolumeTetrapore::setupRegions(){ tcderiv.setCol( 2, crossProduct( d1, Vector(0.0,0.0,1.0) ) ); dcross[2](0,0)=( tcderiv(0,0)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 ); // dx/dx dcross[2](0,1)=( tcderiv(0,1)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 ); // dx/dy - dcross[2](0,2)=( tcderiv(0,2)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 ); // dx/dz + dcross[2](0,2)=( tcderiv(0,2)/crossmod - ucross[0]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 ); // dx/dz dcross[2](1,0)=( tcderiv(1,0)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,0) + ucross[1]*tcderiv(1,0) + ucross[2]*tcderiv(2,0))/cmod3 ); // dy/dx dcross[2](1,1)=( tcderiv(1,1)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,1) + ucross[1]*tcderiv(1,1) + ucross[2]*tcderiv(2,1))/cmod3 ); // dy/dy dcross[2](1,2)=( tcderiv(1,2)/crossmod - ucross[1]*(ucross[0]*tcderiv(0,2) + ucross[1]*tcderiv(1,2) + ucross[2]*tcderiv(2,2))/cmod3 ); // dy/dz @@ -310,38 +310,38 @@ void VolumeTetrapore::setupRegions(){ dtruep[2].setCol( 2, ( crossProduct( dcross[2].getCol(2), bisector ) + crossProduct( cross, dbisector[2].getCol(2) ) ) ); // Now convert these to the derivatives of the true axis - for(unsigned i=0;i<3;++i){ - dbi[i] = cos(pi/4.0)*dbisector[i] + sin(pi/4.0)*dtruep[i]; - dperp[i] = cos(pi/4.0)*dbisector[i] - sin(pi/4.0)*dtruep[i]; + for(unsigned i=0; i<3; ++i) { + dbi[i] = cos(pi/4.0)*dbisector[i] + sin(pi/4.0)*dtruep[i]; + dperp[i] = cos(pi/4.0)*dbisector[i] - sin(pi/4.0)*dtruep[i]; } // Ensure that all lengths are positive - if( len_bi<0 ){ - bi=-bi; len_bi=-len_bi; - for(unsigned i=0;i<3;++i) dbi[i]*=-1.0; + if( len_bi<0 ) { + bi=-bi; len_bi=-len_bi; + for(unsigned i=0; i<3; ++i) dbi[i]*=-1.0; + } + if( len_cross<0 ) { + cross=-cross; len_cross=-len_cross; + for(unsigned i=0; i<3; ++i) dcross[i]*=-1.0; } - if( len_cross<0 ){ - cross=-cross; len_cross=-len_cross; - for(unsigned i=0;i<3;++i) dcross[i]*=-1.0; + if( len_perp<0 ) { + perp=-perp; len_perp=-len_perp; + for(unsigned i=0; i<3; ++i) dperp[i]*=-1.0; } - if( len_perp<0 ){ - perp=-perp; len_perp=-len_perp; - for(unsigned i=0;i<3;++i) dperp[i]*=-1.0; - } if( len_bi<=0 || len_cross<=0 || len_bi<=0 ) plumed_merror("Invalid box coordinates"); // Now derivatives of lengths Tensor dd3( Tensor::identity() ); Vector ddb2=d1; if( lbi==2 ) ddb2=d2; dlbi[1].zero(); dlbi[2].zero(); dlbi[3].zero(); - dlbi[0] = matmul(ddb2,dbi[0]) - matmul(bi,dd3); + dlbi[0] = matmul(ddb2,dbi[0]) - matmul(bi,dd3); dlbi[lbi] = matmul(ddb2,dbi[lbi]) + matmul(bi,dd3); // Derivative wrt d1 - dlcross[0] = matmul(d3,dcross[0]) - matmul(cross,dd3); + dlcross[0] = matmul(d3,dcross[0]) - matmul(cross,dd3); dlcross[1] = matmul(d3,dcross[1]); dlcross[2] = matmul(d3,dcross[2]); dlcross[3] = matmul(cross,dd3); - ddb2=d1; if( lpi==2 ) ddb2=d2; + ddb2=d1; if( lpi==2 ) ddb2=d2; dlperp[1].zero(); dlperp[2].zero(); dlperp[3].zero(); dlperp[0] = matmul(ddb2,dperp[0]) - matmul( perp, dd3 ); dlperp[lpi] = matmul(ddb2,dperp[lpi]) + matmul(perp, dd3); @@ -354,39 +354,39 @@ void VolumeTetrapore::setupRegions(){ jacob_det = fabs( jacob.determinant() ); } -void VolumeTetrapore::update(){ - if(boxout){ - boxfile.printf("%d\n",8); - const Tensor & t(getPbc().getBox()); - if(getPbc().isOrthorombic()){ - boxfile.printf(" %f %f %f\n",lenunit*t(0,0),lenunit*t(1,1),lenunit*t(2,2)); - }else{ - boxfile.printf(" %f %f %f %f %f %f %f %f %f\n", - lenunit*t(0,0),lenunit*t(0,1),lenunit*t(0,2), - lenunit*t(1,0),lenunit*t(1,1),lenunit*t(1,2), - lenunit*t(2,0),lenunit*t(2,1),lenunit*t(2,2) - ); - } - boxfile.printf("AR %f %f %f \n",lenunit*origin[0],lenunit*origin[1],lenunit*origin[2]); - Vector ut, vt, wt; - ut = origin + len_bi*bi; - vt = origin + len_cross*cross; - wt = origin + len_perp*perp; - boxfile.printf("AR %f %f %f \n",lenunit*(ut[0]) , lenunit*(ut[1]), lenunit*(ut[2]) ); - boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]) , lenunit*(vt[1]), lenunit*(vt[2]) ); - boxfile.printf("AR %f %f %f \n",lenunit*(wt[0]) , lenunit*(wt[1]), lenunit*(wt[2]) ); - boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]+len_bi*bi[0]), - lenunit*(vt[1]+len_bi*bi[1]), - lenunit*(vt[2]+len_bi*bi[2]) ); - boxfile.printf("AR %f %f %f \n",lenunit*(ut[0]+len_perp*perp[0]), - lenunit*(ut[1]+len_perp*perp[1]), - lenunit*(ut[2]+len_perp*perp[2]) ); - boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]+len_perp*perp[0]), - lenunit*(vt[1]+len_perp*perp[1]), - lenunit*(vt[2]+len_perp*perp[2]) ); - boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]+len_perp*perp[0]+len_bi*bi[0]), - lenunit*(vt[1]+len_perp*perp[1]+len_bi*bi[1]), - lenunit*(vt[2]+len_perp*perp[2]+len_bi*bi[2]) ); +void VolumeTetrapore::update() { + if(boxout) { + boxfile.printf("%d\n",8); + const Tensor & t(getPbc().getBox()); + if(getPbc().isOrthorombic()) { + boxfile.printf(" %f %f %f\n",lenunit*t(0,0),lenunit*t(1,1),lenunit*t(2,2)); + } else { + boxfile.printf(" %f %f %f %f %f %f %f %f %f\n", + lenunit*t(0,0),lenunit*t(0,1),lenunit*t(0,2), + lenunit*t(1,0),lenunit*t(1,1),lenunit*t(1,2), + lenunit*t(2,0),lenunit*t(2,1),lenunit*t(2,2) + ); + } + boxfile.printf("AR %f %f %f \n",lenunit*origin[0],lenunit*origin[1],lenunit*origin[2]); + Vector ut, vt, wt; + ut = origin + len_bi*bi; + vt = origin + len_cross*cross; + wt = origin + len_perp*perp; + boxfile.printf("AR %f %f %f \n",lenunit*(ut[0]), lenunit*(ut[1]), lenunit*(ut[2]) ); + boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]), lenunit*(vt[1]), lenunit*(vt[2]) ); + boxfile.printf("AR %f %f %f \n",lenunit*(wt[0]), lenunit*(wt[1]), lenunit*(wt[2]) ); + boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]+len_bi*bi[0]), + lenunit*(vt[1]+len_bi*bi[1]), + lenunit*(vt[2]+len_bi*bi[2]) ); + boxfile.printf("AR %f %f %f \n",lenunit*(ut[0]+len_perp*perp[0]), + lenunit*(ut[1]+len_perp*perp[1]), + lenunit*(ut[2]+len_perp*perp[2]) ); + boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]+len_perp*perp[0]), + lenunit*(vt[1]+len_perp*perp[1]), + lenunit*(vt[2]+len_perp*perp[2]) ); + boxfile.printf("AR %f %f %f \n",lenunit*(vt[0]+len_perp*perp[0]+len_bi*bi[0]), + lenunit*(vt[1]+len_perp*perp[1]+len_bi*bi[1]), + lenunit*(vt[2]+len_perp*perp[2]+len_bi*bi[2]) ); } } @@ -402,8 +402,8 @@ double VolumeTetrapore::calculateNumberInside( const Vector& cpos, Vector& deriv bead.set( 0, len_bi, sigma ); double upos=dotProduct( datom, bi ); ucontr=bead.calculate( upos, uder ); - double udlen=bead.uboundDerivative( upos ); - double uder2 = bead.lboundDerivative( upos ) - udlen; + double udlen=bead.uboundDerivative( upos ); + double uder2 = bead.lboundDerivative( upos ) - udlen; // Calculate contribution from integral along cross bead.set( 0, len_cross, sigma ); @@ -423,22 +423,22 @@ double VolumeTetrapore::calculateNumberInside( const Vector& cpos, Vector& deriv derivatives[0] = (dfd[0]*bi[0]+dfd[1]*cross[0]+dfd[2]*perp[0]); derivatives[1] = (dfd[0]*bi[1]+dfd[1]*cross[1]+dfd[2]*perp[1]); derivatives[2] = (dfd[0]*bi[2]+dfd[1]*cross[2]+dfd[2]*perp[2]); - double tot = ucontr*vcontr*wcontr*jacob_det; + double tot = ucontr*vcontr*wcontr*jacob_det; // Add reference atom derivatives dfd[0]=uder2*vcontr*wcontr; dfd[1]=ucontr*vder2*wcontr; dfd[2]=ucontr*vcontr*wder2; Vector dfld; dfld[0]=udlen*vcontr*wcontr; dfld[1]=ucontr*vdlen*wcontr; dfld[2]=ucontr*vcontr*wdlen; rderiv[0] = dfd[0]*matmul(datom,dbi[0]) + dfd[1]*matmul(datom,dcross[0]) + dfd[2]*matmul(datom,dperp[0]) + - dfld[0]*dlbi[0] + dfld[1]*dlcross[0] + dfld[2]*dlperp[0] - derivatives; - rderiv[1] = dfd[0]*matmul(datom,dbi[1]) + dfd[1]*matmul(datom,dcross[1]) + dfd[2]*matmul(datom,dperp[1]) + + dfld[0]*dlbi[0] + dfld[1]*dlcross[0] + dfld[2]*dlperp[0] - derivatives; + rderiv[1] = dfd[0]*matmul(datom,dbi[1]) + dfd[1]*matmul(datom,dcross[1]) + dfd[2]*matmul(datom,dperp[1]) + dfld[0]*dlbi[1] + dfld[1]*dlcross[1] + dfld[2]*dlperp[1]; - rderiv[2] = dfd[0]*matmul(datom,dbi[2]) + dfd[1]*matmul(datom,dcross[2]) + dfd[2]*matmul(datom,dperp[2]) + + rderiv[2] = dfd[0]*matmul(datom,dbi[2]) + dfd[1]*matmul(datom,dcross[2]) + dfd[2]*matmul(datom,dperp[2]) + dfld[0]*dlbi[2] + dfld[1]*dlcross[2] + dfld[2]*dlperp[2]; rderiv[3] = dfld[0]*dlbi[3] + dfld[1]*dlcross[3] + dfld[2]*dlperp[3]; vir.zero(); vir-=Tensor( cpos,derivatives ); - for(unsigned i=0;i<4;++i){ - vir -= Tensor( getPosition(i), rderiv[i] ); + for(unsigned i=0; i<4; ++i) { + vir -= Tensor( getPosition(i), rderiv[i] ); } return tot; diff --git a/src/multicolvar/XAngle.cpp b/src/multicolvar/XAngle.cpp index 2e8791003..fbc2ab1d7 100644 --- a/src/multicolvar/XAngle.cpp +++ b/src/multicolvar/XAngle.cpp @@ -30,17 +30,17 @@ using namespace std; -namespace PLMD{ -namespace multicolvar{ +namespace PLMD { +namespace multicolvar { //+PLUMEDOC MCOLVAR XANGLES /* -Calculate the angles between the vector connecting two atoms and the x axis. +Calculate the angles between the vector connecting two atoms and the x axis. \par Examples The following input tells plumed to calculate the angles between the x-axis and the vector connecting atom 3 to atom 5 and between the x-axis -and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then +and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then \verbatim XANLGES ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1} LABEL=d1 PRINT ARG=d1.min @@ -51,12 +51,12 @@ PRINT ARG=d1.min //+PLUMEDOC MCOLVAR YANGLES /* -Calculate the angles between the vector connecting two atoms and the y axis. +Calculate the angles between the vector connecting two atoms and the y axis. \par Examples The following input tells plumed to calculate the angles between the y-axis and the vector connecting atom 3 to atom 5 and between the y-axis -and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then +and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then \verbatim YANLGES ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1} LABEL=d1 PRINT ARG=d1.min @@ -67,12 +67,12 @@ PRINT ARG=d1.min //+PLUMEDOC MCOLVAR ZANGLES /* -Calculate the angles between the vector connecting two atoms and the z axis. +Calculate the angles between the vector connecting two atoms and the z axis. \par Examples The following input tells plumed to calculate the angles between the z-axis and the vector connecting atom 3 to atom 5 and between the z-axis -and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then +and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then \verbatim ZANLGES ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1} LABEL=d1 PRINT ARG=d1.min @@ -86,7 +86,7 @@ PRINT ARG=d1.min class XAngles : public MultiColvarBase { private: bool use_sf; - unsigned myc; + unsigned myc; SwitchingFunction sf1; public: static void registerKeywords( Keywords& keys ); @@ -95,38 +95,38 @@ public: virtual double compute( const unsigned& tindex, AtomValuePack& myatoms ) const ; double calculateWeight( const unsigned& taskCode, const double& weight, AtomValuePack& ) const ; /// Returns the number of coordinates of the field - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } }; PLUMED_REGISTER_ACTION(XAngles,"XANGLES") PLUMED_REGISTER_ACTION(XAngles,"YANGLES") PLUMED_REGISTER_ACTION(XAngles,"ZANGLES") -void XAngles::registerKeywords( Keywords& keys ){ +void XAngles::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); - keys.use("MAX"); keys.use("ALT_MIN"); + keys.use("MAX"); keys.use("ALT_MIN"); keys.use("MEAN"); keys.use("MIN"); keys.use("LESS_THAN"); - keys.use("LOWEST"); keys.use("HIGHEST"); + keys.use("LOWEST"); keys.use("HIGHEST"); keys.use("MORE_THAN"); keys.use("BETWEEN"); keys.use("HISTOGRAM"); keys.use("MOMENTS"); keys.add("numbered","ATOMS","the atoms involved in each of the angles you wish to calculate. " - "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one angle will be " - "calculated for each ATOM keyword you specify (all ATOM keywords should " - "specify the indices of two atoms). The eventual number of quantities calculated by this " - "action will depend on what functions of the distribution you choose to calculate."); + "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one angle will be " + "calculated for each ATOM keyword you specify (all ATOM keywords should " + "specify the indices of two atoms). The eventual number of quantities calculated by this " + "action will depend on what functions of the distribution you choose to calculate."); keys.reset_style("ATOMS","atoms"); keys.add("atoms-1","GROUP","Calculate the distance between each distinct pair of atoms in the group"); keys.add("atoms-2","GROUPA","Calculate the distances between all the atoms in GROUPA and all " - "the atoms in GROUPB. This must be used in conjuction with GROUPB."); + "the atoms in GROUPB. This must be used in conjuction with GROUPB."); keys.add("atoms-2","GROUPB","Calculate the distances between all the atoms in GROUPA and all the atoms " - "in GROUPB. This must be used in conjuction with GROUPA."); + "in GROUPB. This must be used in conjuction with GROUPA."); keys.add("optional","SWITCH","A switching function that ensures that only angles are only computed when atoms are within " - "are within a certain fixed cutoff. The following provides information on the \\ref switchingfunction that are available."); + "are within a certain fixed cutoff. The following provides information on the \\ref switchingfunction that are available."); } XAngles::XAngles(const ActionOptions&ao): -Action(ao), -MultiColvarBase(ao), -use_sf(false) + Action(ao), + MultiColvarBase(ao), + use_sf(false) { if( getName().find("X")!=std::string::npos) myc=0; else if( getName().find("Y")!=std::string::npos) myc=1; @@ -135,12 +135,12 @@ use_sf(false) // Read in switching function std::string sfinput, errors; parse("SWITCH",sfinput); - if( sfinput.length()>0 ){ - use_sf=true; weightHasDerivatives=true; - sf1.set(sfinput,errors); - if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); - log.printf(" only calculating angles for atoms separated by less than %s\n", sf1.description().c_str() ); - setLinkCellCutoff( sf1.get_dmax() ); + if( sfinput.length()>0 ) { + use_sf=true; weightHasDerivatives=true; + sf1.set(sfinput,errors); + if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); + log.printf(" only calculating angles for atoms separated by less than %s\n", sf1.description().c_str() ); + setLinkCellCutoff( sf1.get_dmax() ); } // Read in the atoms @@ -156,7 +156,7 @@ double XAngles::calculateWeight( const unsigned& taskCode, const double& weight, if(!use_sf) return 1.0; Vector distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); - double dw, w = sf1.calculateSqr( distance.modulo2(), dw ); + double dw, w = sf1.calculateSqr( distance.modulo2(), dw ); addAtomDerivatives( 0, 0, (-dw)*distance, myatoms ); addAtomDerivatives( 0, 1, (+dw)*distance, myatoms ); myatoms.addBoxDerivatives( 0, (-dw)*Tensor(distance,distance) ); @@ -164,14 +164,14 @@ double XAngles::calculateWeight( const unsigned& taskCode, const double& weight, } double XAngles::compute( const unsigned& tindex, AtomValuePack& myatoms ) const { - Vector ddij, ddik, axis, distance; axis.zero(); axis[myc]=1; - distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); - PLMD::Angle a; double angle=a.compute( distance, axis, ddij, ddik ); - - addAtomDerivatives( 1, 0, -ddij, myatoms ); - addAtomDerivatives( 1, 1, ddij, myatoms ); - myatoms.addBoxDerivatives( 1, -Tensor( distance,ddij ) ); - return angle; + Vector ddij, ddik, axis, distance; axis.zero(); axis[myc]=1; + distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); + PLMD::Angle a; double angle=a.compute( distance, axis, ddij, ddik ); + + addAtomDerivatives( 1, 0, -ddij, myatoms ); + addAtomDerivatives( 1, 1, ddij, myatoms ); + myatoms.addBoxDerivatives( 1, -Tensor( distance,ddij ) ); + return angle; } } diff --git a/src/multicolvar/XDistances.cpp b/src/multicolvar/XDistances.cpp index 6bff7887e..009b04de5 100644 --- a/src/multicolvar/XDistances.cpp +++ b/src/multicolvar/XDistances.cpp @@ -28,20 +28,20 @@ using namespace std; -namespace PLMD{ -namespace multicolvar{ +namespace PLMD { +namespace multicolvar { //+PLUMEDOC MCOLVAR XDISTANCES /* -Calculate the x components of the vectors connecting one or many pairs of atoms. +Calculate the x components of the vectors connecting one or many pairs of atoms. You can then calculate functions of the distribution of -values such as the minimum, the number less than a certain quantity and so on. +values such as the minimum, the number less than a certain quantity and so on. \par Examples -The following input tells plumed to calculate the x-component of the vector connecting atom 3 to atom 5 and -the x-component of the vector connecting atom 1 to atom 2. The minimum of these two quantities is then -printed +The following input tells plumed to calculate the x-component of the vector connecting atom 3 to atom 5 and +the x-component of the vector connecting atom 1 to atom 2. The minimum of these two quantities is then +printed \verbatim XDISTANCES ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1} LABEL=d1 PRINT ARG=d1.min @@ -49,8 +49,8 @@ PRINT ARG=d1.min (See also \ref PRINT). -The following input tells plumed to calculate the x-component of the vector connecting atom 3 to atom 5 and -the x-component of the vector connecting atom 1 to atom 2. The number of values that are +The following input tells plumed to calculate the x-component of the vector connecting atom 3 to atom 5 and +the x-component of the vector connecting atom 1 to atom 2. The number of values that are less than 0.1nm is then printed to a file. \verbatim XDISTANCES ATOMS1=3,5 ATOMS2=1,2 LABEL=d1 LESS_THAN={RATIONAL R_0=0.1} @@ -58,8 +58,8 @@ PRINT ARG=d1.lt0.1 \endverbatim (See also \ref PRINT \ref switchingfunction). -The following input tells plumed to calculate the x-components of all the distinct vectors that can be created -between atoms 1, 2 and 3 (i.e. the vectors between atoms 1 and 2, atoms 1 and 3 and atoms 2 and 3). +The following input tells plumed to calculate the x-components of all the distinct vectors that can be created +between atoms 1, 2 and 3 (i.e. the vectors between atoms 1 and 2, atoms 1 and 3 and atoms 2 and 3). The average of these quantities is then calculated. \verbatim XDISTANCES GROUP=1-3 AVERAGE LABEL=d1 @@ -68,11 +68,11 @@ PRINT ARG=d1.average (See also \ref PRINT) The following input tells plumed to calculate all the vectors connecting the the atoms in GROUPA to the atoms in GROUPB. -In other words the vector between atoms 1 and 2 and the vector between atoms 1 and 3. The number of values +In other words the vector between atoms 1 and 2 and the vector between atoms 1 and 3. The number of values more than 0.1 is then printed to a file. \verbatim XDISTANCES GROUPA=1 GROUPB=2,3 MORE_THAN={RATIONAL R_0=0.1} -PRINT ARG=d1.gt0.1 +PRINT ARG=d1.gt0.1 \endverbatim (See also \ref PRINT \ref switchingfunction) */ @@ -80,15 +80,15 @@ PRINT ARG=d1.gt0.1 //+PLUMEDOC MCOLVAR YDISTANCES /* -Calculate the y components of the vectors connecting one or many pairs of atoms. +Calculate the y components of the vectors connecting one or many pairs of atoms. You can then calculate functions of the distribution of values such as the minimum, the number less than a certain quantity and so on. \par Examples -The following input tells plumed to calculate the y-component of the vector connecting atom 3 to atom 5 and -the y-component of the vector connecting atom 1 to atom 2. The minimum of these two quantities is then -printed +The following input tells plumed to calculate the y-component of the vector connecting atom 3 to atom 5 and +the y-component of the vector connecting atom 1 to atom 2. The minimum of these two quantities is then +printed \verbatim YDISTANCES ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1} LABEL=d1 PRINT ARG=d1.min @@ -96,8 +96,8 @@ PRINT ARG=d1.min (See also \ref PRINT). -The following input tells plumed to calculate the y-component of the vector connecting atom 3 to atom 5 and -the y-component of the vector connecting atom 1 to atom 2. The number of values that are +The following input tells plumed to calculate the y-component of the vector connecting atom 3 to atom 5 and +the y-component of the vector connecting atom 1 to atom 2. The number of values that are less than 0.1nm is then printed to a file. \verbatim YDISTANCES ATOMS1=3,5 ATOMS2=1,2 LABEL=d1 LESS_THAN={RATIONAL R_0=0.1} @@ -105,8 +105,8 @@ PRINT ARG=d1.lt0.1 \endverbatim (See also \ref PRINT \ref switchingfunction). -The following input tells plumed to calculate the y-components of all the distinct vectors that can be created -between atoms 1, 2 and 3 (i.e. the vectors between atoms 1 and 2, atoms 1 and 3 and atoms 2 and 3). +The following input tells plumed to calculate the y-components of all the distinct vectors that can be created +between atoms 1, 2 and 3 (i.e. the vectors between atoms 1 and 2, atoms 1 and 3 and atoms 2 and 3). The average of these quantities is then calculated. \verbatim YDISTANCES GROUP=1-3 AVERAGE LABEL=d1 @@ -115,11 +115,11 @@ PRINT ARG=d1.average (See also \ref PRINT) The following input tells plumed to calculate all the vectors connecting the the atoms in GROUPA to the atoms in GROUPB. -In other words the vector between atoms 1 and 2 and the vector between atoms 1 and 3. The number of values +In other words the vector between atoms 1 and 2 and the vector between atoms 1 and 3. The number of values more than 0.1 is then printed to a file. \verbatim YDISTANCES GROUPA=1 GROUPB=2,3 MORE_THAN={RATIONAL R_0=0.1} -PRINT ARG=d1.gt0.1 +PRINT ARG=d1.gt0.1 \endverbatim (See also \ref PRINT \ref switchingfunction) @@ -128,15 +128,15 @@ PRINT ARG=d1.gt0.1 //+PLUMEDOC MCOLVAR ZDISTANCES /* -Calculate the z components of the vectors connecting one or many pairs of atoms. +Calculate the z components of the vectors connecting one or many pairs of atoms. You can then calculate functions of the distribution of values such as the minimum, the number less than a certain quantity and so on. \par Examples -The following input tells plumed to calculate the z-component of the vector connecting atom 3 to atom 5 and -the z-component of the vector connecting atom 1 to atom 2. The minimum of these two quantities is then -printed +The following input tells plumed to calculate the z-component of the vector connecting atom 3 to atom 5 and +the z-component of the vector connecting atom 1 to atom 2. The minimum of these two quantities is then +printed \verbatim ZDISTANCES ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1} LABEL=d1 PRINT ARG=d1.min @@ -144,8 +144,8 @@ PRINT ARG=d1.min (See also \ref PRINT). -The following input tells plumed to calculate the z-component of the vector connecting atom 3 to atom 5 and -the z-component of the vector connecting atom 1 to atom 2. The number of values that are +The following input tells plumed to calculate the z-component of the vector connecting atom 3 to atom 5 and +the z-component of the vector connecting atom 1 to atom 2. The number of values that are less than 0.1nm is then printed to a file. \verbatim ZDISTANCES ATOMS1=3,5 ATOMS2=1,2 LABEL=d1 LESS_THAN={RATIONAL R_0=0.1} @@ -153,8 +153,8 @@ PRINT ARG=d1.lt0.1 \endverbatim (See also \ref PRINT \ref switchingfunction). -The following input tells plumed to calculate the z-components of all the distinct vectors that can be created -between atoms 1, 2 and 3 (i.e. the vectors between atoms 1 and 2, atoms 1 and 3 and atoms 2 and 3). +The following input tells plumed to calculate the z-components of all the distinct vectors that can be created +between atoms 1, 2 and 3 (i.e. the vectors between atoms 1 and 2, atoms 1 and 3 and atoms 2 and 3). The average of these quantities is then calculated. \verbatim ZDISTANCES GROUP=1-3 AVERAGE LABEL=d1 @@ -163,11 +163,11 @@ PRINT ARG=d1.average (See also \ref PRINT) The following input tells plumed to calculate all the vectors connecting the the atoms in GROUPA to the atoms in GROUPB. -In other words the vector between atoms 1 and 2 and the vector between atoms 1 and 3. The number of values +In other words the vector between atoms 1 and 2 and the vector between atoms 1 and 3. The number of values more than 0.1 is then printed to a file. \verbatim ZDISTANCES GROUPA=1 GROUPB=2,3 MORE_THAN={RATIONAL R_0=0.1} -PRINT ARG=d1.gt0.1 +PRINT ARG=d1.gt0.1 \endverbatim (See also \ref PRINT \ref switchingfunction) @@ -184,35 +184,35 @@ public: // active methods: virtual double compute( const unsigned& tindex, AtomValuePack& myatoms ) const ; /// Returns the number of coordinates of the field - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } }; PLUMED_REGISTER_ACTION(XDistances,"XDISTANCES") PLUMED_REGISTER_ACTION(XDistances,"YDISTANCES") PLUMED_REGISTER_ACTION(XDistances,"ZDISTANCES") -void XDistances::registerKeywords( Keywords& keys ){ +void XDistances::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); - keys.use("MAX"); keys.use("ALT_MIN"); + keys.use("MAX"); keys.use("ALT_MIN"); keys.use("MEAN"); keys.use("MIN"); keys.use("LESS_THAN"); - keys.use("LOWEST"); keys.use("HIGHEST"); + keys.use("LOWEST"); keys.use("HIGHEST"); keys.use("MORE_THAN"); keys.use("BETWEEN"); keys.use("HISTOGRAM"); keys.use("MOMENTS"); keys.add("numbered","ATOMS","the atoms involved in each of the distances you wish to calculate. " - "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one distance will be " - "calculated for each ATOM keyword you specify (all ATOM keywords should " - "specify the indices of two atoms). The eventual number of quantities calculated by this " - "action will depend on what functions of the distribution you choose to calculate."); + "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one distance will be " + "calculated for each ATOM keyword you specify (all ATOM keywords should " + "specify the indices of two atoms). The eventual number of quantities calculated by this " + "action will depend on what functions of the distribution you choose to calculate."); keys.reset_style("ATOMS","atoms"); keys.add("atoms-1","GROUP","Calculate the distance between each distinct pair of atoms in the group"); keys.add("atoms-2","GROUPA","Calculate the distances between all the atoms in GROUPA and all " - "the atoms in GROUPB. This must be used in conjuction with GROUPB."); + "the atoms in GROUPB. This must be used in conjuction with GROUPB."); keys.add("atoms-2","GROUPB","Calculate the distances between all the atoms in GROUPA and all the atoms " - "in GROUPB. This must be used in conjuction with GROUPA."); + "in GROUPB. This must be used in conjuction with GROUPA."); } XDistances::XDistances(const ActionOptions&ao): -Action(ao), -MultiColvarBase(ao) + Action(ao), + MultiColvarBase(ao) { if( getName().find("X")!=std::string::npos) myc=0; else if( getName().find("Y")!=std::string::npos) myc=1; @@ -229,16 +229,16 @@ MultiColvarBase(ao) } double XDistances::compute( const unsigned& tindex, AtomValuePack& myatoms ) const { - Vector distance; - distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); - const double value=distance[myc]; - - Vector myvec; myvec.zero(); - // And finish the calculation - myvec[myc]=+1; addAtomDerivatives( 1, 1, myvec, myatoms ); - myvec[myc]=-1; addAtomDerivatives( 1, 0, myvec, myatoms ); - myatoms.addBoxDerivatives( 1, Tensor(distance,myvec) ); - return value; + Vector distance; + distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); + const double value=distance[myc]; + + Vector myvec; myvec.zero(); + // And finish the calculation + myvec[myc]=+1; addAtomDerivatives( 1, 1, myvec, myatoms ); + myvec[myc]=-1; addAtomDerivatives( 1, 0, myvec, myatoms ); + myatoms.addBoxDerivatives( 1, Tensor(distance,myvec) ); + return value; } } diff --git a/src/multicolvar/XYDistances.cpp b/src/multicolvar/XYDistances.cpp index a6a2e978a..767c64a86 100644 --- a/src/multicolvar/XYDistances.cpp +++ b/src/multicolvar/XYDistances.cpp @@ -28,21 +28,21 @@ using namespace std; -namespace PLMD{ -namespace multicolvar{ +namespace PLMD { +namespace multicolvar { //+PLUMEDOC MCOLVAR XYDISTANCES /* -Calculate distance between a pair of atoms neglecting the z-component. +Calculate distance between a pair of atoms neglecting the z-component. You can then calculate functions of the distribution of -values such as the minimum, the number less than a certain quantity and so on. +values such as the minimum, the number less than a certain quantity and so on. \par Examples -The following input tells plumed to calculate the projection of the length of the vector connecting atom 3 -to atom 5 projected in the xy-plane and the projection of the length of the vector -the vector connecting atom 1 to atom 2 in the xy-plane. The minimum of these two quantities is then -printed +The following input tells plumed to calculate the projection of the length of the vector connecting atom 3 +to atom 5 projected in the xy-plane and the projection of the length of the vector +the vector connecting atom 1 to atom 2 in the xy-plane. The minimum of these two quantities is then +printed \verbatim XYDISTANCES ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1} LABEL=d1 PRINT ARG=d1.min @@ -54,16 +54,16 @@ PRINT ARG=d1.min //+PLUMEDOC MCOLVAR XZDISTANCES /* -Calculate distance between a pair of atoms neglecting the y-component. +Calculate distance between a pair of atoms neglecting the y-component. You can then calculate functions of the distribution of -values such as the minimum, the number less than a certain quantity and so on. +values such as the minimum, the number less than a certain quantity and so on. \par Examples -The following input tells plumed to calculate the projection of the length of the vector connecting atom 3 -to atom 5 projected in the xz-plane and the projection of the length of the vector -the vector connecting atom 1 to atom 2 in the xz-plane. The minimum of these two quantities is then -printed +The following input tells plumed to calculate the projection of the length of the vector connecting atom 3 +to atom 5 projected in the xz-plane and the projection of the length of the vector +the vector connecting atom 1 to atom 2 in the xz-plane. The minimum of these two quantities is then +printed \verbatim XZDISTANCES ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1} LABEL=d1 PRINT ARG=d1.min @@ -75,16 +75,16 @@ PRINT ARG=d1.min //+PLUMEDOC MCOLVAR YZDISTANCES /* -Calculate distance between a pair of atoms neglecting the x-component. +Calculate distance between a pair of atoms neglecting the x-component. You can then calculate functions of the distribution of -values such as the minimum, the number less than a certain quantity and so on. +values such as the minimum, the number less than a certain quantity and so on. \par Examples -The following input tells plumed to calculate the projection of the length of the vector connecting atom 3 -to atom 5 in the yz-plane and the projection of the length of the vector -the vector connecting atom 1 to atom 2 in the yz-plane. The minimum of these two quantities is then -printed +The following input tells plumed to calculate the projection of the length of the vector connecting atom 3 +to atom 5 in the yz-plane and the projection of the length of the vector +the vector connecting atom 1 to atom 2 in the yz-plane. The minimum of these two quantities is then +printed \verbatim YZDISTANCES ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1} LABEL=d1 PRINT ARG=d1.min @@ -104,41 +104,41 @@ public: // active methods: virtual double compute( const unsigned& tindex, AtomValuePack& myatoms ) const ; /// Returns the number of coordinates of the field - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } }; PLUMED_REGISTER_ACTION(XYDistances,"XYDISTANCES") PLUMED_REGISTER_ACTION(XYDistances,"XZDISTANCES") PLUMED_REGISTER_ACTION(XYDistances,"YZDISTANCES") -void XYDistances::registerKeywords( Keywords& keys ){ +void XYDistances::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); - keys.use("MAX"); keys.use("ALT_MIN"); - keys.use("MEAN"); keys.use("MIN"); keys.use("LESS_THAN"); keys.use("LOWEST"); keys.use("HIGHEST"); + keys.use("MAX"); keys.use("ALT_MIN"); + keys.use("MEAN"); keys.use("MIN"); keys.use("LESS_THAN"); keys.use("LOWEST"); keys.use("HIGHEST"); keys.use("MORE_THAN"); keys.use("BETWEEN"); keys.use("HISTOGRAM"); keys.use("MOMENTS"); keys.add("numbered","ATOMS","the atoms involved in each of the distances you wish to calculate. " - "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one distance will be " - "calculated for each ATOM keyword you specify (all ATOM keywords should " - "specify the incides of two atoms). The eventual number of quantities calculated by this " - "action will depend on what functions of the distribution you choose to calculate."); + "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one distance will be " + "calculated for each ATOM keyword you specify (all ATOM keywords should " + "specify the incides of two atoms). The eventual number of quantities calculated by this " + "action will depend on what functions of the distribution you choose to calculate."); keys.reset_style("ATOMS","atoms"); keys.add("atoms-1","GROUP","Calculate the distance between each distinct pair of atoms in the group"); keys.add("atoms-2","GROUPA","Calculate the distances between all the atoms in GROUPA and all " - "the atoms in GROUPB. This must be used in conjuction with GROUPB."); + "the atoms in GROUPB. This must be used in conjuction with GROUPB."); keys.add("atoms-2","GROUPB","Calculate the distances between all the atoms in GROUPA and all the atoms " - "in GROUPB. This must be used in conjuction with GROUPA."); + "in GROUPB. This must be used in conjuction with GROUPA."); } XYDistances::XYDistances(const ActionOptions&ao): -Action(ao), -MultiColvarBase(ao) + Action(ao), + MultiColvarBase(ao) { - if( getName().find("XY")!=std::string::npos){ - myc1=0; myc2=1; - } else if( getName().find("XZ")!=std::string::npos){ - myc1=0; myc2=2; - } else if( getName().find("YZ")!=std::string::npos){ - myc1=1; myc2=2; + if( getName().find("XY")!=std::string::npos) { + myc1=0; myc2=1; + } else if( getName().find("XZ")!=std::string::npos) { + myc1=0; myc2=2; + } else if( getName().find("YZ")!=std::string::npos) { + myc1=1; myc2=2; } else plumed_error(); // Read in the atoms @@ -151,17 +151,17 @@ MultiColvarBase(ao) } double XYDistances::compute( const unsigned& tindex, AtomValuePack& myatoms ) const { - Vector distance; - distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); - const double value=sqrt(distance[myc1]*distance[myc1] + distance[myc2]*distance[myc2] ); - const double invvalue=1.0/value; - - Vector myvec; myvec.zero(); - // And finish the calculation - myvec[myc1]=+invvalue*distance[myc1]; myvec[myc2]=+invvalue*distance[myc2]; addAtomDerivatives( 1, 1, myvec, myatoms ); - myvec[myc1]=-invvalue*distance[myc1]; myvec[myc2]=-invvalue*distance[myc2]; addAtomDerivatives( 1, 0, myvec, myatoms ); - myatoms.addBoxDerivatives( 1, Tensor(distance,myvec) ); - return value; + Vector distance; + distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); + const double value=sqrt(distance[myc1]*distance[myc1] + distance[myc2]*distance[myc2] ); + const double invvalue=1.0/value; + + Vector myvec; myvec.zero(); + // And finish the calculation + myvec[myc1]=+invvalue*distance[myc1]; myvec[myc2]=+invvalue*distance[myc2]; addAtomDerivatives( 1, 1, myvec, myatoms ); + myvec[myc1]=-invvalue*distance[myc1]; myvec[myc2]=-invvalue*distance[myc2]; addAtomDerivatives( 1, 0, myvec, myatoms ); + myatoms.addBoxDerivatives( 1, Tensor(distance,myvec) ); + return value; } } diff --git a/src/multicolvar/XYTorsion.cpp b/src/multicolvar/XYTorsion.cpp index a263a2abd..fd512799a 100644 --- a/src/multicolvar/XYTorsion.cpp +++ b/src/multicolvar/XYTorsion.cpp @@ -30,17 +30,17 @@ using namespace std; -namespace PLMD{ -namespace multicolvar{ +namespace PLMD { +namespace multicolvar { //+PLUMEDOC MCOLVAR XYTORSIONS /* -Calculate the torsional angle around the x axis from the positive y direction. +Calculate the torsional angle around the x axis from the positive y direction. \par Examples -The following input tells plumed to calculate the angle around the x direction between the positive y-axis and the vector connecting atom 3 to atom 5 and -the angle around the x direction between the positive y axis and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then output +The following input tells plumed to calculate the angle around the x direction between the positive y-axis and the vector connecting atom 3 to atom 5 and +the angle around the x direction between the positive y axis and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then output \verbatim XYTORSIONS ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1} LABEL=d1 PRINT ARG=d1.min @@ -51,12 +51,12 @@ PRINT ARG=d1.min //+PLUMEDOC MCOLVAR XZTORSIONS /* -Calculate the torsional angle around the x axis from the positive z direction. +Calculate the torsional angle around the x axis from the positive z direction. \par Examples -The following input tells plumed to calculate the angle around the x direction between the positive z-axis and the vector connecting atom 3 to atom 5 and -the angle around the x direction between the positive z direction and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then output +The following input tells plumed to calculate the angle around the x direction between the positive z-axis and the vector connecting atom 3 to atom 5 and +the angle around the x direction between the positive z direction and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then output \verbatim XZTORSIONS ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1} LABEL=d1 PRINT ARG=d1.min @@ -67,12 +67,12 @@ PRINT ARG=d1.min //+PLUMEDOC MCOLVAR YXTORSIONS /* -Calculate the torsional angle around the y axis from the positive x direction. +Calculate the torsional angle around the y axis from the positive x direction. \par Examples -The following input tells plumed to calculate the angle around the y direction between the positive x-direction and the vector connecting atom 3 to atom 5 and -the angle around the y direction between the positive x axis and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then output +The following input tells plumed to calculate the angle around the y direction between the positive x-direction and the vector connecting atom 3 to atom 5 and +the angle around the y direction between the positive x axis and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then output \verbatim YXTORSIONS ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1} LABEL=d1 PRINT ARG=d1.min @@ -83,12 +83,12 @@ PRINT ARG=d1.min //+PLUMEDOC MCOLVAR YZTORSIONS /* -Calculate the torsional angle around the y axis from the positive z direction. +Calculate the torsional angle around the y axis from the positive z direction. \par Examples -The following input tells plumed to calculate the angle around the y direction between the positive z-direction and the vector connecting atom 3 to atom 5 and -the angle around the y direction between the positive z direction and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then output +The following input tells plumed to calculate the angle around the y direction between the positive z-direction and the vector connecting atom 3 to atom 5 and +the angle around the y direction between the positive z direction and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then output \verbatim YZTORSIONS ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1} LABEL=d1 PRINT ARG=d1.min @@ -99,12 +99,12 @@ PRINT ARG=d1.min //+PLUMEDOC MCOLVAR ZXTORSIONS /* -Calculate the torsional angle around the z axis from the positive x direction. +Calculate the torsional angle around the z axis from the positive x direction. \par Examples -The following input tells plumed to calculate the angle around the z direction between the positive x-direction and the vector connecting atom 3 to atom 5 and -the angle around the z direction between the positive x-direction and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then output +The following input tells plumed to calculate the angle around the z direction between the positive x-direction and the vector connecting atom 3 to atom 5 and +the angle around the z direction between the positive x-direction and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then output \verbatim ZXTORSIONS ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1} LABEL=d1 PRINT ARG=d1.min @@ -115,12 +115,12 @@ PRINT ARG=d1.min //+PLUMEDOC MCOLVAR ZYTORSIONS /* -Calculate the torsional angle around the z axis from the positive y direction. +Calculate the torsional angle around the z axis from the positive y direction. \par Examples -The following input tells plumed to calculate the angle around the z direction between the positive y-axis and the vector connecting atom 3 to atom 5 and -the angle around the z direction between the positive y axis and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then output +The following input tells plumed to calculate the angle around the z direction between the positive y-axis and the vector connecting atom 3 to atom 5 and +the angle around the z direction between the positive y axis and the vector connecting atom 1 to atom 2. The minimum of these two quantities is then output \verbatim ZYTORSIONS ATOMS1=3,5 ATOMS2=1,2 MIN={BETA=0.1} LABEL=d1 PRINT ARG=d1.min @@ -135,7 +135,7 @@ PRINT ARG=d1.min class XYTorsion : public MultiColvarBase { private: bool use_sf; - unsigned myc1, myc2; + unsigned myc1, myc2; SwitchingFunction sf1; public: static void registerKeywords( Keywords& keys ); @@ -144,8 +144,8 @@ public: virtual double compute( const unsigned& tindex, AtomValuePack& myatoms ) const ; double calculateWeight( const unsigned& taskCode, const double& weight, AtomValuePack& ) const ; /// Returns the number of coordinates of the field - bool isPeriodic(){ return true; } - void retrieveDomain( std::string& min, std::string& max){ min="-pi"; max="pi"; } + bool isPeriodic() { return true; } + void retrieveDomain( std::string& min, std::string& max) { min="-pi"; max="pi"; } }; PLUMED_REGISTER_ACTION(XYTorsion,"XYTORSIONS") @@ -155,48 +155,48 @@ PLUMED_REGISTER_ACTION(XYTorsion,"YZTORSIONS") PLUMED_REGISTER_ACTION(XYTorsion,"ZXTORSIONS") PLUMED_REGISTER_ACTION(XYTorsion,"ZYTORSIONS") -void XYTorsion::registerKeywords( Keywords& keys ){ +void XYTorsion::registerKeywords( Keywords& keys ) { MultiColvarBase::registerKeywords( keys ); - keys.use("MAX"); keys.use("ALT_MIN"); - keys.use("MEAN"); keys.use("MIN"); - keys.use("LOWEST"); keys.use("HIGHEST"); + keys.use("MAX"); keys.use("ALT_MIN"); + keys.use("MEAN"); keys.use("MIN"); + keys.use("LOWEST"); keys.use("HIGHEST"); keys.use("BETWEEN"); keys.use("HISTOGRAM"); keys.use("MOMENTS"); keys.add("numbered","ATOMS","the atoms involved in each of the torsions you wish to calculate. " - "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one torsion will be " - "calculated for each ATOM keyword you specify (all ATOM keywords should " - "specify the incides of two atoms). The eventual number of quantities calculated by this " - "action will depend on what functions of the distribution you choose to calculate."); + "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one torsion will be " + "calculated for each ATOM keyword you specify (all ATOM keywords should " + "specify the incides of two atoms). The eventual number of quantities calculated by this " + "action will depend on what functions of the distribution you choose to calculate."); keys.reset_style("ATOMS","atoms"); keys.add("atoms-1","GROUP","Calculate the distance between each distinct pair of atoms in the group"); keys.add("atoms-2","GROUPA","Calculate the distances between all the atoms in GROUPA and all " - "the atoms in GROUPB. This must be used in conjuction with GROUPB."); + "the atoms in GROUPB. This must be used in conjuction with GROUPB."); keys.add("atoms-2","GROUPB","Calculate the distances between all the atoms in GROUPA and all the atoms " - "in GROUPB. This must be used in conjuction with GROUPA."); + "in GROUPB. This must be used in conjuction with GROUPA."); keys.add("optional","SWITCH","A switching function that ensures that only angles are only computed when atoms are within " - "are within a certain fixed cutoff. The following provides information on the \\ref switchingfunction that are available."); + "are within a certain fixed cutoff. The following provides information on the \\ref switchingfunction that are available."); } XYTorsion::XYTorsion(const ActionOptions&ao): -Action(ao), -MultiColvarBase(ao), -use_sf(false) + Action(ao), + MultiColvarBase(ao), + use_sf(false) { - if( getName().find("XY")!=std::string::npos){ myc1=0; myc2=1; } - else if( getName().find("XZ")!=std::string::npos){ myc1=0; myc2=2; } - else if( getName().find("YX")!=std::string::npos){ myc1=1; myc2=0; } - else if( getName().find("YZ")!=std::string::npos){ myc1=1; myc2=2; } - else if( getName().find("ZX")!=std::string::npos){ myc1=2; myc2=0; } - else if( getName().find("ZY")!=std::string::npos){ myc1=2; myc2=1; } + if( getName().find("XY")!=std::string::npos) { myc1=0; myc2=1; } + else if( getName().find("XZ")!=std::string::npos) { myc1=0; myc2=2; } + else if( getName().find("YX")!=std::string::npos) { myc1=1; myc2=0; } + else if( getName().find("YZ")!=std::string::npos) { myc1=1; myc2=2; } + else if( getName().find("ZX")!=std::string::npos) { myc1=2; myc2=0; } + else if( getName().find("ZY")!=std::string::npos) { myc1=2; myc2=1; } else plumed_error(); // Read in switching function std::string sfinput, errors; parse("SWITCH",sfinput); - if( sfinput.length()>0 ){ - use_sf=true; weightHasDerivatives=true; - sf1.set(sfinput,errors); - if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); - log.printf(" only calculating angles for atoms separated by less than %s\n", sf1.description().c_str() ); - setLinkCellCutoff( sf1.get_dmax() ); + if( sfinput.length()>0 ) { + use_sf=true; weightHasDerivatives=true; + sf1.set(sfinput,errors); + if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors ); + log.printf(" only calculating angles for atoms separated by less than %s\n", sf1.description().c_str() ); + setLinkCellCutoff( sf1.get_dmax() ); } // Read in the atoms @@ -212,7 +212,7 @@ double XYTorsion::calculateWeight( const unsigned& taskCode, const double& weigh if(!use_sf) return 1.0; Vector distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); - double dw, w = sf1.calculateSqr( distance.modulo2(), dw ); + double dw, w = sf1.calculateSqr( distance.modulo2(), dw ); addAtomDerivatives( 0, 0, (-dw)*distance, myatoms ); addAtomDerivatives( 0, 1, (+dw)*distance, myatoms ); myatoms.addBoxDerivatives( 0, (-dw)*Tensor(distance,distance) ); @@ -220,15 +220,15 @@ double XYTorsion::calculateWeight( const unsigned& taskCode, const double& weigh } double XYTorsion::compute( const unsigned& tindex, AtomValuePack& myatoms ) const { - Vector dd0, dd1, dd2, axis, rot, distance; - axis.zero(); rot.zero(); rot[myc1]=1; axis[myc2]=1; - distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); - PLMD::Torsion t; double torsion=t.compute( distance, rot, axis, dd0, dd1, dd2 ); - - addAtomDerivatives( 1, 0, -dd0, myatoms ); - addAtomDerivatives( 1, 1, dd0, myatoms ); - myatoms.addBoxDerivatives( 1, -extProduct(distance,dd0) ); - return torsion; + Vector dd0, dd1, dd2, axis, rot, distance; + axis.zero(); rot.zero(); rot[myc1]=1; axis[myc2]=1; + distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) ); + PLMD::Torsion t; double torsion=t.compute( distance, rot, axis, dd0, dd1, dd2 ); + + addAtomDerivatives( 1, 0, -dd0, myatoms ); + addAtomDerivatives( 1, 1, dd0, myatoms ); + myatoms.addBoxDerivatives( 1, -extProduct(distance,dd0) ); + return torsion; } } diff --git a/src/reference/ArgumentOnlyDistance.cpp b/src/reference/ArgumentOnlyDistance.cpp index 4664044af..0e4a3e2ae 100644 --- a/src/reference/ArgumentOnlyDistance.cpp +++ b/src/reference/ArgumentOnlyDistance.cpp @@ -25,24 +25,24 @@ namespace PLMD { ArgumentOnlyDistance::ArgumentOnlyDistance( const ReferenceConfigurationOptions& ro ): -ReferenceConfiguration(ro), -ReferenceArguments(ro) + ReferenceConfiguration(ro), + ReferenceArguments(ro) { } -void ArgumentOnlyDistance::read( const PDB& pdb ){ +void ArgumentOnlyDistance::read( const PDB& pdb ) { readArgumentsFromPDB( pdb ); } double ArgumentOnlyDistance::calculate( const std::vector<Value*>& vals, ReferenceValuePack& myder, const bool& squared ) const { std::vector<double> tmparg( vals.size() ); - for(unsigned i=0;i<vals.size();++i) tmparg[i]=vals[i]->get(); + for(unsigned i=0; i<vals.size(); ++i) tmparg[i]=vals[i]->get(); double d=calculateArgumentDistance( vals, tmparg, myder, squared ); if( !myder.updateComplete() ) myder.updateDynamicLists(); return d; } -double ArgumentOnlyDistance::calc( const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& vals, const std::vector<double>& arg, +double ArgumentOnlyDistance::calc( const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& vals, const std::vector<double>& arg, ReferenceValuePack& myder, const bool& squared ) const { plumed_dbg_assert( pos.size()==0 ); double d=calculateArgumentDistance( vals, arg, myder, squared ); diff --git a/src/reference/ArgumentOnlyDistance.h b/src/reference/ArgumentOnlyDistance.h index 67923c17b..3636f0764 100644 --- a/src/reference/ArgumentOnlyDistance.h +++ b/src/reference/ArgumentOnlyDistance.h @@ -35,8 +35,8 @@ class ArgumentOnlyDistance : public ReferenceArguments { public: explicit ArgumentOnlyDistance( const ReferenceConfigurationOptions& ro ); void read( const PDB& pdb ); - bool pcaIsEnabledForThisReference(){ return true; } - void setupPCAStorage( ReferenceValuePack& mypack ){ mypack.switchOnPCAOption(); } + bool pcaIsEnabledForThisReference() { return true; } + void setupPCAStorage( ReferenceValuePack& mypack ) { mypack.switchOnPCAOption(); } double calc( const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& vals, const std::vector<double>& arg, ReferenceValuePack& myder, const bool& squared ) const ; double calculate( const std::vector<Value*>& vals, ReferenceValuePack& myder, const bool& squared ) const ; }; diff --git a/src/reference/DRMSD.cpp b/src/reference/DRMSD.cpp index d9ee501a6..88183ac5d 100644 --- a/src/reference/DRMSD.cpp +++ b/src/reference/DRMSD.cpp @@ -28,84 +28,84 @@ namespace PLMD { PLUMED_REGISTER_METRIC(DRMSD,"DRMSD") DRMSD::DRMSD( const ReferenceConfigurationOptions& ro ): -ReferenceConfiguration( ro ), -SingleDomainRMSD( ro ), -nopbc(true), -bounds_were_set(false), -lower(0), -upper(std::numeric_limits<double>::max( )) + ReferenceConfiguration( ro ), + SingleDomainRMSD( ro ), + nopbc(true), + bounds_were_set(false), + lower(0), + upper(std::numeric_limits<double>::max( )) { } -void DRMSD::setBoundsOnDistances( bool dopbc, double lbound, double ubound ){ - bounds_were_set=true; nopbc=!dopbc; +void DRMSD::setBoundsOnDistances( bool dopbc, double lbound, double ubound ) { + bounds_were_set=true; nopbc=!dopbc; lower=lbound; upper=ubound; } -void DRMSD::readBounds(){ - parseFlag("NOPBC",nopbc); +void DRMSD::readBounds() { + parseFlag("NOPBC",nopbc); parse("LOWER_CUTOFF",lower,true); parse("UPPER_CUTOFF",upper,true); setBoundsOnDistances( !nopbc, lower, upper ); } -void DRMSD::read( const PDB& pdb ){ +void DRMSD::read( const PDB& pdb ) { readAtomsFromPDB( pdb ); readBounds(); setup_targets(); } -void DRMSD::setReferenceAtoms( const std::vector<Vector>& conf, const std::vector<double>& align_in, const std::vector<double>& displace_in ){ +void DRMSD::setReferenceAtoms( const std::vector<Vector>& conf, const std::vector<double>& align_in, const std::vector<double>& displace_in ) { SingleDomainRMSD::setReferenceAtoms( conf, align_in, displace_in ); setup_targets(); } -void DRMSD::setup_targets(){ +void DRMSD::setup_targets() { plumed_massert( bounds_were_set, "I am missing a call to DRMSD::setBoundsOnDistances"); unsigned natoms = getNumberOfReferencePositions(); - for(unsigned i=0;i<natoms-1;++i){ - for(unsigned j=i+1;j<natoms;++j){ - double distance = delta( getReferencePosition(i), getReferencePosition(j) ).modulo(); - if(distance < upper && distance > lower ){ - targets[std::make_pair(i,j)] = distance; - } - } + for(unsigned i=0; i<natoms-1; ++i) { + for(unsigned j=i+1; j<natoms; ++j) { + double distance = delta( getReferencePosition(i), getReferencePosition(j) ).modulo(); + if(distance < upper && distance > lower ) { + targets[std::make_pair(i,j)] = distance; + } + } } - if( targets.empty() ) error("drmsd will compare no distances - check upper and lower bounds are sensible"); + if( targets.empty() ) error("drmsd will compare no distances - check upper and lower bounds are sensible"); } double DRMSD::calc( const std::vector<Vector>& pos, const Pbc& pbc, ReferenceValuePack& myder, const bool& squared ) const { plumed_dbg_assert(!targets.empty()); - Vector distance; - myder.clear(); - double drmsd=0.; - for(const auto & it : targets){ - - const unsigned i=getAtomIndex( it.first.first ); - const unsigned j=getAtomIndex( it.first.second ); - - if(nopbc) distance=delta( pos[i] , pos[j] ); - else distance=pbc.distance( pos[i] , pos[j] ); - - const double len = distance.modulo(); - const double diff = len - it.second; - const double der = diff / len; - - drmsd += diff * diff; - myder.addAtomDerivatives( i, -der * distance ); - myder.addAtomDerivatives( j, der * distance ); - myder.addBoxDerivatives( - der * Tensor(distance,distance) ); + Vector distance; + myder.clear(); + double drmsd=0.; + for(const auto & it : targets) { + + const unsigned i=getAtomIndex( it.first.first ); + const unsigned j=getAtomIndex( it.first.second ); + + if(nopbc) distance=delta( pos[i], pos[j] ); + else distance=pbc.distance( pos[i], pos[j] ); + + const double len = distance.modulo(); + const double diff = len - it.second; + const double der = diff / len; + + drmsd += diff * diff; + myder.addAtomDerivatives( i, -der * distance ); + myder.addAtomDerivatives( j, der * distance ); + myder.addBoxDerivatives( - der * Tensor(distance,distance) ); } const double inpairs = 1./static_cast<double>(targets.size()); double idrmsd; - if(squared){ - drmsd = drmsd * inpairs; - idrmsd = 2.0 * inpairs; + if(squared) { + drmsd = drmsd * inpairs; + idrmsd = 2.0 * inpairs; } else { - drmsd = sqrt( drmsd * inpairs ); - idrmsd = inpairs / drmsd ; + drmsd = sqrt( drmsd * inpairs ); + idrmsd = inpairs / drmsd ; } myder.scaleAllDerivatives( idrmsd ); diff --git a/src/reference/DRMSD.h b/src/reference/DRMSD.h index 634d03162..e99f382f4 100644 --- a/src/reference/DRMSD.h +++ b/src/reference/DRMSD.h @@ -35,12 +35,12 @@ private: protected: bool bounds_were_set; double lower, upper; - std::map< std::pair <unsigned,unsigned> , double> targets; + std::map< std::pair <unsigned,unsigned>, double> targets; /// Read in NOPBC, LOWER_CUTOFF and UPPER_CUTOFF void readBounds(); public: explicit DRMSD( const ReferenceConfigurationOptions& ro ); -/// This sets upper and lower bounds on distances to be used in DRMSD +/// This sets upper and lower bounds on distances to be used in DRMSD void setBoundsOnDistances( bool dopbc, double lbound=0.0, double ubound=std::numeric_limits<double>::max( ) ); /// Check that similar comparisons are being performed - perhaps this is needed ask Davide? GAT // void check( ReferenceConfiguration* , ReferenceConfiguration* ); diff --git a/src/reference/Direction.cpp b/src/reference/Direction.cpp index fa04b643d..5e50e9b33 100644 --- a/src/reference/Direction.cpp +++ b/src/reference/Direction.cpp @@ -27,47 +27,47 @@ namespace PLMD { PLUMED_REGISTER_METRIC(Direction,"DIRECTION") Direction::Direction( const ReferenceConfigurationOptions& ro ): -ReferenceConfiguration(ro), -ReferenceAtoms(ro), -ReferenceArguments(ro) + ReferenceConfiguration(ro), + ReferenceAtoms(ro), + ReferenceArguments(ro) { } -void Direction::read( const PDB& pdb ){ +void Direction::read( const PDB& pdb ) { readAtomsFromPDB( pdb ); readArgumentsFromPDB( pdb ); } -void Direction::setDirection( const std::vector<Vector>& conf, const std::vector<double>& args ){ +void Direction::setDirection( const std::vector<Vector>& conf, const std::vector<double>& args ) { std::vector<double> sigma( args.size(), 1.0 ); setReferenceArguments( args, sigma ); reference_atoms.resize( conf.size() ); align.resize( conf.size() ); displace.resize( conf.size() ); atom_der_index.resize( conf.size() ); - for(unsigned i=0;i<conf.size();++i){ align[i]=1.0; displace[i]=1.0; atom_der_index[i]=i; reference_atoms[i]=conf[i]; } + for(unsigned i=0; i<conf.size(); ++i) { align[i]=1.0; displace[i]=1.0; atom_der_index[i]=i; reference_atoms[i]=conf[i]; } } -void Direction::addDirection( const double& weight, const Direction& dir ){ +void Direction::addDirection( const double& weight, const Direction& dir ) { plumed_dbg_assert( dir.getNumberOfReferenceArguments()==getNumberOfReferenceArguments() && dir.reference_atoms.size()==reference_atoms.size() ); - for(unsigned i=0;i<reference_args.size();++i) reference_args[i] += weight*dir.reference_args[i]; - for(unsigned i=0;i<reference_atoms.size();++i) reference_atoms[i] += weight*dir.reference_atoms[i]; + for(unsigned i=0; i<reference_args.size(); ++i) reference_args[i] += weight*dir.reference_args[i]; + for(unsigned i=0; i<reference_atoms.size(); ++i) reference_atoms[i] += weight*dir.reference_atoms[i]; } -void Direction::zeroDirection(){ - for(unsigned i=0;i<reference_args.size();++i) reference_args[i] = 0.; - for(unsigned i=0;i<reference_atoms.size();++i) reference_atoms[i].zero(); +void Direction::zeroDirection() { + for(unsigned i=0; i<reference_args.size(); ++i) reference_args[i] = 0.; + for(unsigned i=0; i<reference_atoms.size(); ++i) reference_atoms[i].zero(); } double Direction::calc( const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& vals, const std::vector<double>& args, ReferenceValuePack& myder, const bool& squared ) const { - plumed_merror("You should never be calling calc for a direction"); return 1.0; + plumed_merror("You should never be calling calc for a direction"); return 1.0; } void Direction::extractArgumentDisplacement( const std::vector<Value*>& vals, const std::vector<double>& arg, std::vector<double>& dirout ) const { - for(unsigned i=0;i<getNumberOfReferenceArguments();++i) dirout[i]=getReferenceArgument(i); + for(unsigned i=0; i<getNumberOfReferenceArguments(); ++i) dirout[i]=getReferenceArgument(i); } void Direction::extractAtomicDisplacement( const std::vector<Vector>& pos, const bool& anflag, std::vector<Vector>& dirout ) const { - for(unsigned i=0;i<getNumberOfAtoms();++i) dirout[i]=getReferencePosition(i); + for(unsigned i=0; i<getNumberOfAtoms(); ++i) dirout[i]=getReferencePosition(i); } } diff --git a/src/reference/Direction.h b/src/reference/Direction.h index 3ac67239a..ced2ac415 100644 --- a/src/reference/Direction.h +++ b/src/reference/Direction.h @@ -28,8 +28,8 @@ namespace PLMD { class Direction : -public ReferenceAtoms, -public ReferenceArguments + public ReferenceAtoms, + public ReferenceArguments { public: explicit Direction( const ReferenceConfigurationOptions& ro ); @@ -38,10 +38,10 @@ public: ReferenceValuePack& myder, const bool& squared ) const ; void setDirection( const std::vector<Vector>& conf, const std::vector<double>& args ); void addDirection( const double& weight, const Direction& dir ); - void setReferenceAtoms( const std::vector<Vector>& conf, const std::vector<double>& align_in, const std::vector<double>& displace_in ){ plumed_error(); } -/// This allows us to extract the reference positions, which are the direction in this case + void setReferenceAtoms( const std::vector<Vector>& conf, const std::vector<double>& align_in, const std::vector<double>& displace_in ) { plumed_error(); } +/// This allows us to extract the reference positions, which are the direction in this case void extractArgumentDisplacement( const std::vector<Value*>& vals, const std::vector<double>& arg, std::vector<double>& dirout ) const ; - void extractAtomicDisplacement( const std::vector<Vector>& pos, const bool& anflag, std::vector<Vector>& dirout ) const ; + void extractAtomicDisplacement( const std::vector<Vector>& pos, const bool& anflag, std::vector<Vector>& dirout ) const ; void zeroDirection(); }; diff --git a/src/reference/DotProductDistance.cpp b/src/reference/DotProductDistance.cpp index bfda1290c..0b0f4eb73 100644 --- a/src/reference/DotProductDistance.cpp +++ b/src/reference/DotProductDistance.cpp @@ -35,18 +35,18 @@ public: PLUMED_REGISTER_METRIC(DotProductDistance,"DOTPRODUCT") DotProductDistance::DotProductDistance( const ReferenceConfigurationOptions& ro ): -ReferenceConfiguration(ro), -ArgumentOnlyDistance(ro) + ReferenceConfiguration(ro), + ArgumentOnlyDistance(ro) { } -void DotProductDistance::read( const PDB& pdb ){ +void DotProductDistance::read( const PDB& pdb ) { readArgumentsFromPDB( pdb ); } -double DotProductDistance::calculateArgumentDistance( const std::vector<Value*> & vals, const std::vector<double>& arg, - ReferenceValuePack& myder, const bool& squared ) const { - double dot=0.0; +double DotProductDistance::calculateArgumentDistance( const std::vector<Value*> & vals, const std::vector<double>& arg, + ReferenceValuePack& myder, const bool& squared ) const { + double dot=0.0; for (unsigned long i=0; i<vals.size(); ++i) dot+=getReferenceArgument(i)*arg[i]; for (unsigned long i=0; i<vals.size(); ++i) myder.setArgumentDerivatives( i, -getReferenceArgument(i)/dot ); return -log(dot); diff --git a/src/reference/EuclideanDistance.cpp b/src/reference/EuclideanDistance.cpp index 791a0a439..244e16c66 100644 --- a/src/reference/EuclideanDistance.cpp +++ b/src/reference/EuclideanDistance.cpp @@ -32,8 +32,8 @@ public: PLUMED_REGISTER_METRIC(EuclideanDistance,"EUCLIDEAN") EuclideanDistance::EuclideanDistance( const ReferenceConfigurationOptions& ro ): -ReferenceConfiguration(ro), -ArgumentOnlyDistance(ro) + ReferenceConfiguration(ro), + ArgumentOnlyDistance(ro) { } diff --git a/src/reference/FakeFrame.h b/src/reference/FakeFrame.h index f6bb9cb0c..2929d725b 100644 --- a/src/reference/FakeFrame.h +++ b/src/reference/FakeFrame.h @@ -27,13 +27,13 @@ namespace PLMD { class FakeFrame : -public PLMD::ReferenceConfiguration + public PLMD::ReferenceConfiguration { public: explicit FakeFrame( const ReferenceConfigurationOptions& ro ) : ReferenceConfiguration(ro) {} - void read( const PDB& ){ plumed_merror("should not be called"); } - double calc( const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& vals, const std::vector<double>& arg, ReferenceValuePack& myder, const bool& squared ) const { - plumed_merror("should not be called"); return 1.0; + void read( const PDB& ) { plumed_merror("should not be called"); } + double calc( const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& vals, const std::vector<double>& arg, ReferenceValuePack& myder, const bool& squared ) const { + plumed_merror("should not be called"); return 1.0; } }; diff --git a/src/reference/IntermolecularDRMSD.cpp b/src/reference/IntermolecularDRMSD.cpp index 223a43f3b..6903c8352 100644 --- a/src/reference/IntermolecularDRMSD.cpp +++ b/src/reference/IntermolecularDRMSD.cpp @@ -31,37 +31,37 @@ private: public: explicit IntermolecularDRMSD( const ReferenceConfigurationOptions& ro ); void read( const PDB& pdb ); - void setup_targets(); + void setup_targets(); }; PLUMED_REGISTER_METRIC(IntermolecularDRMSD,"INTER-DRMSD") IntermolecularDRMSD::IntermolecularDRMSD( const ReferenceConfigurationOptions& ro ): -ReferenceConfiguration( ro ), -DRMSD( ro ), -nblocks(0) + ReferenceConfiguration( ro ), + DRMSD( ro ), + nblocks(0) { } -void IntermolecularDRMSD::read( const PDB& pdb ){ +void IntermolecularDRMSD::read( const PDB& pdb ) { readAtomsFromPDB( pdb, true ); nblocks = pdb.getNumberOfAtomBlocks(); blocks.resize( nblocks+1 ); if( nblocks==1 ) error("Trying to compute intermolecular rmsd but found no TERs in input PDB"); - blocks[0]=0; for(unsigned i=0;i<nblocks;++i) blocks[i+1]=pdb.getAtomBlockEnds()[i]; + blocks[0]=0; for(unsigned i=0; i<nblocks; ++i) blocks[i+1]=pdb.getAtomBlockEnds()[i]; readBounds(); setup_targets(); } -void IntermolecularDRMSD::setup_targets(){ +void IntermolecularDRMSD::setup_targets() { plumed_massert( bounds_were_set, "I am missing a call to DRMSD::setBoundsOnDistances"); - for(unsigned i=1;i<nblocks;++i){ - for(unsigned j=0;j<i;++j){ - for(unsigned iatom=blocks[i];iatom<blocks[i+1];++iatom){ - for(unsigned jatom=blocks[j];jatom<blocks[j+1];++jatom){ - double distance = delta( getReferencePosition(iatom), getReferencePosition(jatom) ).modulo(); - if(distance < upper && distance > lower ) targets[std::make_pair(iatom,jatom)] = distance; - } - } + for(unsigned i=1; i<nblocks; ++i) { + for(unsigned j=0; j<i; ++j) { + for(unsigned iatom=blocks[i]; iatom<blocks[i+1]; ++iatom) { + for(unsigned jatom=blocks[j]; jatom<blocks[j+1]; ++jatom) { + double distance = delta( getReferencePosition(iatom), getReferencePosition(jatom) ).modulo(); + if(distance < upper && distance > lower ) targets[std::make_pair(iatom,jatom)] = distance; + } } + } } } diff --git a/src/reference/IntramolecularDRMSD.cpp b/src/reference/IntramolecularDRMSD.cpp index cd7b022c9..2a7b4b64f 100644 --- a/src/reference/IntramolecularDRMSD.cpp +++ b/src/reference/IntramolecularDRMSD.cpp @@ -31,35 +31,35 @@ private: public: explicit IntramolecularDRMSD( const ReferenceConfigurationOptions& ro ); void read( const PDB& pdb ); - void setup_targets(); + void setup_targets(); }; PLUMED_REGISTER_METRIC(IntramolecularDRMSD,"INTRA-DRMSD") IntramolecularDRMSD::IntramolecularDRMSD( const ReferenceConfigurationOptions& ro ): -ReferenceConfiguration( ro ), -DRMSD( ro ), -nblocks(0) + ReferenceConfiguration( ro ), + DRMSD( ro ), + nblocks(0) { } -void IntramolecularDRMSD::read( const PDB& pdb ){ +void IntramolecularDRMSD::read( const PDB& pdb ) { readAtomsFromPDB( pdb, true ); nblocks = pdb.getNumberOfAtomBlocks(); blocks.resize( nblocks+1 ); if( nblocks==1 ) error("Trying to compute intramolecular rmsd but found no TERs in input PDB"); - blocks[0]=0; for(unsigned i=0;i<nblocks;++i) blocks[i+1]=pdb.getAtomBlockEnds()[i]; + blocks[0]=0; for(unsigned i=0; i<nblocks; ++i) blocks[i+1]=pdb.getAtomBlockEnds()[i]; readBounds(); setup_targets(); } -void IntramolecularDRMSD::setup_targets(){ +void IntramolecularDRMSD::setup_targets() { plumed_massert( bounds_were_set, "I am missing a call to DRMSD::setBoundsOnDistances"); - for(unsigned i=0;i<nblocks;++i){ - for(unsigned iatom=blocks[i]+1;iatom<blocks[i+1];++iatom){ - for(unsigned jatom=blocks[i];jatom<iatom;++jatom){ - double distance = delta( getReferencePosition(iatom), getReferencePosition(jatom) ).modulo(); - if(distance < upper && distance > lower ) targets[std::make_pair(iatom,jatom)] = distance; - } + for(unsigned i=0; i<nblocks; ++i) { + for(unsigned iatom=blocks[i]+1; iatom<blocks[i+1]; ++iatom) { + for(unsigned jatom=blocks[i]; jatom<iatom; ++jatom) { + double distance = delta( getReferencePosition(iatom), getReferencePosition(jatom) ).modulo(); + if(distance < upper && distance > lower ) targets[std::make_pair(iatom,jatom)] = distance; } + } } } diff --git a/src/reference/MahalanobisDistance.cpp b/src/reference/MahalanobisDistance.cpp index 7a50bf5e0..19a3e9669 100644 --- a/src/reference/MahalanobisDistance.cpp +++ b/src/reference/MahalanobisDistance.cpp @@ -32,8 +32,8 @@ public: PLUMED_REGISTER_METRIC(MahalanobisDistance,"MAHALANOBIS") MahalanobisDistance::MahalanobisDistance( const ReferenceConfigurationOptions& ro ): -ReferenceConfiguration(ro), -ArgumentOnlyDistance(ro) + ReferenceConfiguration(ro), + ArgumentOnlyDistance(ro) { hasmetric=true; } diff --git a/src/reference/MetricRegister.cpp b/src/reference/MetricRegister.cpp index 0c240fa0f..dfff4d5e0 100644 --- a/src/reference/MetricRegister.cpp +++ b/src/reference/MetricRegister.cpp @@ -22,35 +22,35 @@ #include "MetricRegister.h" #include <iostream> -namespace PLMD{ +namespace PLMD { -MetricRegister::~MetricRegister(){ - if(m.size()>0){ +MetricRegister::~MetricRegister() { + if(m.size()>0) { std::string names=""; for(const auto & p : m) names+=p.first+" "; std::cerr<<"WARNING: ReferenceConfiguration "+ names +" has not been properly unregistered. This might lead to memory leak!!\n"; } } -MetricRegister& metricRegister(){ +MetricRegister& metricRegister() { static MetricRegister ans; return ans; } -void MetricRegister::remove(creator_pointer f){ - for(auto p=m.begin();p!=m.end();++p){ - if((*p).second==f){ +void MetricRegister::remove(creator_pointer f) { + for(auto p=m.begin(); p!=m.end(); ++p) { + if((*p).second==f) { m.erase(p); break; } } } -void MetricRegister::add( std::string type, creator_pointer f ){ +void MetricRegister::add( std::string type, creator_pointer f ) { plumed_massert(m.count(type)==0,"type has already been registered"); m.insert(std::pair<std::string,creator_pointer>(type,f)); } -bool MetricRegister::check(std::string type){ +bool MetricRegister::check(std::string type) { if( m.count(type)>0 ) return true; return false; } diff --git a/src/reference/MetricRegister.h b/src/reference/MetricRegister.h index 91b44a590..64cb3424e 100644 --- a/src/reference/MetricRegister.h +++ b/src/reference/MetricRegister.h @@ -31,11 +31,11 @@ #include "tools/PDB.h" #include "ReferenceConfiguration.h" -namespace PLMD{ +namespace PLMD { class PDB; -class MetricRegister{ +class MetricRegister { private: /// Pointer to a function which, given the type for a ReferenceConfiguration, creates it typedef ReferenceConfiguration*(*creator_pointer)(const ReferenceConfigurationOptions&); @@ -53,9 +53,9 @@ public: /// Create a reference configuration and don't set a point of reference template <class T> T* create( const std::string& type ); -/// Create a reference configuration and set the point of reference from the pdb +/// Create a reference configuration and set the point of reference from the pdb template <class T> - T* create( const std::string& type , const PDB& pdb ); + T* create( const std::string& type, const PDB& pdb ); }; MetricRegister& metricRegister(); @@ -69,13 +69,13 @@ MetricRegister& metricRegister(); } classname##RegisterMeObject; template <class T> -T* MetricRegister::create( const std::string& type ){ +T* MetricRegister::create( const std::string& type ) { std::string ftype; - if( type.find("MULTI-")!=std::string::npos ){ - ftype="MULTI"; + if( type.find("MULTI-")!=std::string::npos ) { + ftype="MULTI"; } else { - std::size_t dash=type.find("-FAST"); // We must remove the fast label - ftype=type.substr(0,dash); + std::size_t dash=type.find("-FAST"); // We must remove the fast label + ftype=type.substr(0,dash); } plumed_massert( check(ftype), "metric " + ftype + " does not exist" ); ReferenceConfigurationOptions ro( type ); @@ -86,16 +86,16 @@ T* MetricRegister::create( const std::string& type ){ } template <class T> -T* MetricRegister::create( const std::string& type, const PDB& pdb ){ +T* MetricRegister::create( const std::string& type, const PDB& pdb ) { std::string rtype; - if( type.length()==0 ){ - std::vector<std::string> remarks( pdb.getRemark() ); - bool found=Tools::parse( remarks, "TYPE", rtype ); - if(!found) plumed_merror("TYPE not specified in pdb input file"); + if( type.length()==0 ) { + std::vector<std::string> remarks( pdb.getRemark() ); + bool found=Tools::parse( remarks, "TYPE", rtype ); + if(!found) plumed_merror("TYPE not specified in pdb input file"); } else { - rtype=type; - } - T* confout=create<T>( rtype ); + rtype=type; + } + T* confout=create<T>( rtype ); confout->set( pdb ); return confout; } diff --git a/src/reference/MultiDomainRMSD.cpp b/src/reference/MultiDomainRMSD.cpp index c6ef4ae7e..fc0bcca62 100644 --- a/src/reference/MultiDomainRMSD.cpp +++ b/src/reference/MultiDomainRMSD.cpp @@ -29,125 +29,125 @@ namespace PLMD { PLUMED_REGISTER_METRIC(MultiDomainRMSD,"MULTI") MultiDomainRMSD::MultiDomainRMSD( const ReferenceConfigurationOptions& ro ): -ReferenceConfiguration(ro), -ReferenceAtoms(ro), -ftype(ro.getMultiRMSDType()) + ReferenceConfiguration(ro), + ReferenceAtoms(ro), + ftype(ro.getMultiRMSDType()) { } -MultiDomainRMSD::~MultiDomainRMSD(){ - for(unsigned i=0;i<domains.size();++i) delete domains[i]; +MultiDomainRMSD::~MultiDomainRMSD() { + for(unsigned i=0; i<domains.size(); ++i) delete domains[i]; } -void MultiDomainRMSD::read( const PDB& pdb ){ - unsigned nblocks = pdb.getNumberOfAtomBlocks(); - if( nblocks<2 ) error("multidomain RMSD only has one block of atoms"); - - std::vector<Vector> positions; std::vector<double> align, displace; - std::string num; blocks.resize( nblocks+1 ); blocks[0]=0; - for(unsigned i=0;i<nblocks;++i) blocks[i+1]=pdb.getAtomBlockEnds()[i]; - - double lower=0.0, upper=std::numeric_limits<double>::max( ); - parse("LOWER_CUTOFF",lower,true); - parse("UPPER_CUTOFF",upper,true); - bool nopbc=false; parseFlag("NOPBC",nopbc); - - for(unsigned i=1;i<=nblocks;++i){ - Tools::convert(i,num); - if( ftype=="RMSD" ){ - parse("TYPE"+num, ftype ); - parse("LOWER_CUTOFF"+num,lower,true); - parse("UPPER_CUTOFF"+num,upper,true); - nopbc=false; parseFlag("NOPBC"+num,nopbc); - } - domains.push_back( metricRegister().create<SingleDomainRMSD>( ftype ) ); - positions.resize( blocks[i] - blocks[i-1] ); - align.resize( blocks[i] - blocks[i-1] ); - displace.resize( blocks[i] - blocks[i-1] ); - unsigned n=0; - for(unsigned j=blocks[i-1];j<blocks[i];++j){ - positions[n]=pdb.getPositions()[j]; - align[n]=pdb.getOccupancy()[j]; - displace[n]=pdb.getBeta()[j]; - n++; - } - domains[i-1]->setBoundsOnDistances( !nopbc, lower, upper ); - domains[i-1]->setReferenceAtoms( positions, align, displace ); - domains[i-1]->setupRMSDObject(); - - double ww=0; parse("WEIGHT"+num, ww, true ); - if( ww==0 ) weights.push_back( 1.0 ); - else weights.push_back( ww ); - } - // And set the atom numbers for this object - setAtomNumbers( pdb.getAtomNumbers() ); +void MultiDomainRMSD::read( const PDB& pdb ) { + unsigned nblocks = pdb.getNumberOfAtomBlocks(); + if( nblocks<2 ) error("multidomain RMSD only has one block of atoms"); + + std::vector<Vector> positions; std::vector<double> align, displace; + std::string num; blocks.resize( nblocks+1 ); blocks[0]=0; + for(unsigned i=0; i<nblocks; ++i) blocks[i+1]=pdb.getAtomBlockEnds()[i]; + + double lower=0.0, upper=std::numeric_limits<double>::max( ); + parse("LOWER_CUTOFF",lower,true); + parse("UPPER_CUTOFF",upper,true); + bool nopbc=false; parseFlag("NOPBC",nopbc); + + for(unsigned i=1; i<=nblocks; ++i) { + Tools::convert(i,num); + if( ftype=="RMSD" ) { + parse("TYPE"+num, ftype ); + parse("LOWER_CUTOFF"+num,lower,true); + parse("UPPER_CUTOFF"+num,upper,true); + nopbc=false; parseFlag("NOPBC"+num,nopbc); + } + domains.push_back( metricRegister().create<SingleDomainRMSD>( ftype ) ); + positions.resize( blocks[i] - blocks[i-1] ); + align.resize( blocks[i] - blocks[i-1] ); + displace.resize( blocks[i] - blocks[i-1] ); + unsigned n=0; + for(unsigned j=blocks[i-1]; j<blocks[i]; ++j) { + positions[n]=pdb.getPositions()[j]; + align[n]=pdb.getOccupancy()[j]; + displace[n]=pdb.getBeta()[j]; + n++; + } + domains[i-1]->setBoundsOnDistances( !nopbc, lower, upper ); + domains[i-1]->setReferenceAtoms( positions, align, displace ); + domains[i-1]->setupRMSDObject(); + + double ww=0; parse("WEIGHT"+num, ww, true ); + if( ww==0 ) weights.push_back( 1.0 ); + else weights.push_back( ww ); + } + // And set the atom numbers for this object + setAtomNumbers( pdb.getAtomNumbers() ); } -void MultiDomainRMSD::setReferenceAtoms( const std::vector<Vector>& conf, const std::vector<double>& align_in, const std::vector<double>& displace_in ){ +void MultiDomainRMSD::setReferenceAtoms( const std::vector<Vector>& conf, const std::vector<double>& align_in, const std::vector<double>& displace_in ) { plumed_error(); } double MultiDomainRMSD::calculate( const std::vector<Vector>& pos, const Pbc& pbc, ReferenceValuePack& myder, const bool& squared ) const { - double totd=0.; Tensor tvirial; std::vector<Vector> mypos; MultiValue tvals( 1, 3*pos.size()+9 ); + double totd=0.; Tensor tvirial; std::vector<Vector> mypos; MultiValue tvals( 1, 3*pos.size()+9 ); ReferenceValuePack tder( 0, getNumberOfAtoms(), tvals ); myder.clear(); - for(unsigned i=0;i<domains.size();++i){ - // Must extract appropriate positions here - mypos.resize( blocks[i+1] - blocks[i] ); - if( myder.calcUsingPCAOption() ) domains[i]->setupPCAStorage( tder ); - unsigned n=0; for(unsigned j=blocks[i];j<blocks[i+1];++j){ tder.setAtomIndex(n,j); mypos[n]=pos[j]; n++; } - for(unsigned k=n;k<getNumberOfAtoms();++k) tder.setAtomIndex(k,3*pos.size()+10); - // This actually does the calculation - totd += weights[i]*domains[i]->calculate( mypos, pbc, tder, true ); - // Now merge the derivative - myder.copyScaledDerivatives( 0, weights[i], tvals ); - // If PCA copy PCA stuff - if( myder.calcUsingPCAOption() ){ - unsigned n=0; - if( tder.centeredpos.size()>0 ) myder.rot[i]=tder.rot[0]; - for(unsigned j=blocks[i];j<blocks[i+1];++j){ - myder.displacement[j]=weights[i]*tder.displacement[n]; // Multiplication by weights here ensures that normalisation is done correctly - if( tder.centeredpos.size()>0 ){ - myder.centeredpos[j]=tder.centeredpos[n]; - for(unsigned p=0;p<3;++p) for(unsigned q=0;q<3;++q) myder.DRotDPos(p,q)[j]=tder.DRotDPos(p,q)[n]; - } - n++; + for(unsigned i=0; i<domains.size(); ++i) { + // Must extract appropriate positions here + mypos.resize( blocks[i+1] - blocks[i] ); + if( myder.calcUsingPCAOption() ) domains[i]->setupPCAStorage( tder ); + unsigned n=0; for(unsigned j=blocks[i]; j<blocks[i+1]; ++j) { tder.setAtomIndex(n,j); mypos[n]=pos[j]; n++; } + for(unsigned k=n; k<getNumberOfAtoms(); ++k) tder.setAtomIndex(k,3*pos.size()+10); + // This actually does the calculation + totd += weights[i]*domains[i]->calculate( mypos, pbc, tder, true ); + // Now merge the derivative + myder.copyScaledDerivatives( 0, weights[i], tvals ); + // If PCA copy PCA stuff + if( myder.calcUsingPCAOption() ) { + unsigned n=0; + if( tder.centeredpos.size()>0 ) myder.rot[i]=tder.rot[0]; + for(unsigned j=blocks[i]; j<blocks[i+1]; ++j) { + myder.displacement[j]=weights[i]*tder.displacement[n]; // Multiplication by weights here ensures that normalisation is done correctly + if( tder.centeredpos.size()>0 ) { + myder.centeredpos[j]=tder.centeredpos[n]; + for(unsigned p=0; p<3; ++p) for(unsigned q=0; q<3; ++q) myder.DRotDPos(p,q)[j]=tder.DRotDPos(p,q)[n]; } - } - // Make sure virial status is set correctly in output derivative pack - // This is only done here so I do this by using class friendship - if( tder.virialWasSet() ) myder.boxWasSet=true; + n++; + } + } + // Make sure virial status is set correctly in output derivative pack + // This is only done here so I do this by using class friendship + if( tder.virialWasSet() ) myder.boxWasSet=true; } if( !myder.updateComplete() ) myder.updateDynamicLists(); - if( !squared ){ - totd=sqrt(totd); double xx=0.5/totd; - myder.scaleAllDerivatives( xx ); + if( !squared ) { + totd=sqrt(totd); double xx=0.5/totd; + myder.scaleAllDerivatives( xx ); } return totd; } -double MultiDomainRMSD::calc( const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& vals, const std::vector<double>& arg, +double MultiDomainRMSD::calc( const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& vals, const std::vector<double>& arg, ReferenceValuePack& myder, const bool& squared ) const { plumed_dbg_assert( vals.size()==0 && pos.size()==getNumberOfAtoms() && arg.size()==0 ); return calculate( pos, pbc, myder, squared ); } -bool MultiDomainRMSD::pcaIsEnabledForThisReference(){ - bool enabled=true; - for(unsigned i=0;i<domains.size();++i){ - if( !domains[i]->pcaIsEnabledForThisReference() ) enabled=false; +bool MultiDomainRMSD::pcaIsEnabledForThisReference() { + bool enabled=true; + for(unsigned i=0; i<domains.size(); ++i) { + if( !domains[i]->pcaIsEnabledForThisReference() ) enabled=false; } return enabled; } -void MultiDomainRMSD::setupPCAStorage( ReferenceValuePack& mypack ){ +void MultiDomainRMSD::setupPCAStorage( ReferenceValuePack& mypack ) { plumed_dbg_assert( pcaIsEnabledForThisReference() ); mypack.switchOnPCAOption(); mypack.displacement.resize( getNumberOfAtoms() ); mypack.centeredpos.resize( getNumberOfAtoms() ); mypack.DRotDPos.resize(3,3); mypack.rot.resize( domains.size() ); - for(unsigned i=0;i<3;++i) for(unsigned j=0;j<3;++j) mypack.DRotDPos(i,j).resize( getNumberOfAtoms() ); + for(unsigned i=0; i<3; ++i) for(unsigned j=0; j<3; ++j) mypack.DRotDPos(i,j).resize( getNumberOfAtoms() ); } // Vector MultiDomainRMSD::getAtomicDisplacement( const unsigned& iatom ){ @@ -161,47 +161,47 @@ void MultiDomainRMSD::setupPCAStorage( ReferenceValuePack& mypack ){ // } void MultiDomainRMSD::extractAtomicDisplacement( const std::vector<Vector>& pos, const bool& anflag, std::vector<Vector>& direction ) const { - std::vector<Vector> mypos, mydir; - for(unsigned i=0;i<domains.size();++i){ - // Must extract appropriate positions here - mypos.resize( blocks[i+1] - blocks[i] ); mydir.resize( blocks[i+1] - blocks[i] ); - unsigned n=0; for(unsigned j=blocks[i];j<blocks[i+1];++j){ mypos[n]=pos[j]; n++; } - // Do the calculation - domains[i]->extractAtomicDisplacement( mypos, anflag, mydir ); - // Extract the direction - n=0; for(unsigned j=blocks[i];j<blocks[i+1];++j){ direction[j]=weights[i]*mydir[n]; n++; } - } + std::vector<Vector> mypos, mydir; + for(unsigned i=0; i<domains.size(); ++i) { + // Must extract appropriate positions here + mypos.resize( blocks[i+1] - blocks[i] ); mydir.resize( blocks[i+1] - blocks[i] ); + unsigned n=0; for(unsigned j=blocks[i]; j<blocks[i+1]; ++j) { mypos[n]=pos[j]; n++; } + // Do the calculation + domains[i]->extractAtomicDisplacement( mypos, anflag, mydir ); + // Extract the direction + n=0; for(unsigned j=blocks[i]; j<blocks[i+1]; ++j) { direction[j]=weights[i]*mydir[n]; n++; } + } } double MultiDomainRMSD::projectAtomicDisplacementOnVector( const std::vector<Vector>& vecs, const std::vector<Vector>& pos, ReferenceValuePack& mypack ) const { - double totd=0.; std::vector<Vector> tvecs; std::vector<Vector> mypos; mypack.clear(); - MultiValue tvals( 1, mypack.getNumberOfDerivatives() ); ReferenceValuePack tder( 0, getNumberOfAtoms(), tvals ); - for(unsigned i=0;i<domains.size();++i){ - // Must extract appropriate positions here - mypos.resize( blocks[i+1] - blocks[i] ); tvecs.resize( blocks[i+1] - blocks[i] ); - domains[i]->setupPCAStorage( tder ); - if( tder.centeredpos.size()>0 ){ - for(unsigned p=0;p<3;++p) for(unsigned q=0;q<3;++q) tder.DRotDPos(p,q).resize( mypos.size() ); + double totd=0.; std::vector<Vector> tvecs; std::vector<Vector> mypos; mypack.clear(); + MultiValue tvals( 1, mypack.getNumberOfDerivatives() ); ReferenceValuePack tder( 0, getNumberOfAtoms(), tvals ); + for(unsigned i=0; i<domains.size(); ++i) { + // Must extract appropriate positions here + mypos.resize( blocks[i+1] - blocks[i] ); tvecs.resize( blocks[i+1] - blocks[i] ); + domains[i]->setupPCAStorage( tder ); + if( tder.centeredpos.size()>0 ) { + for(unsigned p=0; p<3; ++p) for(unsigned q=0; q<3; ++q) tder.DRotDPos(p,q).resize( mypos.size() ); + } + // Extract information from storage pack and put in local pack + if( tder.centeredpos.size()>0 ) tder.rot[0]=mypack.rot[i]; + unsigned n=0; + for(unsigned j=blocks[i]; j<blocks[i+1]; ++j) { + mypos[n]=pos[j]; tder.setAtomIndex(n,j); tvecs[n] = vecs[j]; + tder.displacement[n]=mypack.displacement[j] / weights[i]; + if( tder.centeredpos.size()>0 ) { + tder.centeredpos[n]=mypack.centeredpos[j]; + for(unsigned p=0; p<3; ++p) for(unsigned q=0; q<3; ++q) tder.DRotDPos(p,q)[n]=mypack.DRotDPos(p,q)[j]; } - // Extract information from storage pack and put in local pack - if( tder.centeredpos.size()>0 ) tder.rot[0]=mypack.rot[i]; - unsigned n=0; - for(unsigned j=blocks[i];j<blocks[i+1];++j){ - mypos[n]=pos[j]; tder.setAtomIndex(n,j); tvecs[n] = vecs[j]; - tder.displacement[n]=mypack.displacement[j] / weights[i]; - if( tder.centeredpos.size()>0 ){ - tder.centeredpos[n]=mypack.centeredpos[j]; - for(unsigned p=0;p<3;++p) for(unsigned q=0;q<3;++q) tder.DRotDPos(p,q)[n]=mypack.DRotDPos(p,q)[j]; - } - n++; - } - for(unsigned k=n;k<getNumberOfAtoms();++k) tder.setAtomIndex(k,3*pos.size()+10); - - // Do the calculations - totd += weights[i]*domains[i]->projectAtomicDisplacementOnVector( tvecs, mypos, tder ); - - // And derivatives - mypack.copyScaledDerivatives( 0, weights[i], tvals ); + n++; + } + for(unsigned k=n; k<getNumberOfAtoms(); ++k) tder.setAtomIndex(k,3*pos.size()+10); + + // Do the calculations + totd += weights[i]*domains[i]->projectAtomicDisplacementOnVector( tvecs, mypos, tder ); + + // And derivatives + mypack.copyScaledDerivatives( 0, weights[i], tvals ); } if( !mypack.updateComplete() ) mypack.updateDynamicLists(); diff --git a/src/reference/MultiDomainRMSD.h b/src/reference/MultiDomainRMSD.h index ed2e5ad30..524f42f42 100644 --- a/src/reference/MultiDomainRMSD.h +++ b/src/reference/MultiDomainRMSD.h @@ -51,8 +51,8 @@ public: /// bool pcaIsEnabledForThisReference(); void extractAtomicDisplacement( const std::vector<Vector>& pos, const bool& anflag, std::vector<Vector>& direction ) const ; - double projectAtomicDisplacementOnVector( const std::vector<Vector>& vecs, const std::vector<Vector>& pos, ReferenceValuePack& mypack ) const ; - void setupPCAStorage( ReferenceValuePack& mypack ); + double projectAtomicDisplacementOnVector( const std::vector<Vector>& vecs, const std::vector<Vector>& pos, ReferenceValuePack& mypack ) const ; + void setupPCAStorage( ReferenceValuePack& mypack ); }; } diff --git a/src/reference/MultiReferenceBase.cpp b/src/reference/MultiReferenceBase.cpp index bdbe148d0..3468d1c13 100644 --- a/src/reference/MultiReferenceBase.cpp +++ b/src/reference/MultiReferenceBase.cpp @@ -26,25 +26,25 @@ namespace PLMD { MultiReferenceBase::MultiReferenceBase( const std::string& type, const bool& checksoff ): -wasSet(false), -skipchecks(checksoff), -mtype(type) + wasSet(false), + skipchecks(checksoff), + mtype(type) { if(checksoff) plumed_assert( mtype.length()==0 ); } -MultiReferenceBase::~MultiReferenceBase(){ - for(unsigned i=0;i<frames.size();++i) delete frames[i]; +MultiReferenceBase::~MultiReferenceBase() { + for(unsigned i=0; i<frames.size(); ++i) delete frames[i]; } -void MultiReferenceBase::clearFrames(){ - for(unsigned i=0;i<frames.size();++i) delete frames[i]; - frames.resize(0); +void MultiReferenceBase::clearFrames() { + for(unsigned i=0; i<frames.size(); ++i) delete frames[i]; + frames.resize(0); clearRestOfData(); } -void MultiReferenceBase::readFrame( PDB& mypdb ){ - wasSet=true; +void MultiReferenceBase::readFrame( PDB& mypdb ) { + wasSet=true; // If skipchecks are enabled metric types must be specified in the input file ReferenceConfiguration* mymsd=metricRegister().create<ReferenceConfiguration>( mtype, mypdb ); // Save everything @@ -55,11 +55,11 @@ void MultiReferenceBase::readFrame( PDB& mypdb ){ mymsd->checkRead(); } -void MultiReferenceBase::getAtomAndArgumentRequirements( std::vector<AtomNumber>& atoms, std::vector<std::string>& args ){ +void MultiReferenceBase::getAtomAndArgumentRequirements( std::vector<AtomNumber>& atoms, std::vector<std::string>& args ) { plumed_assert( atoms.size()==0 && args.size()==0 ); - for(unsigned i=0;i<frames.size();++i){ - frames[i]->getAtomRequests( atoms ); - frames[i]->getArgumentRequests( args ); + for(unsigned i=0; i<frames.size(); ++i) { + frames[i]->getAtomRequests( atoms ); + frames[i]->getArgumentRequests( args ); } } @@ -70,7 +70,7 @@ void MultiReferenceBase::getAtomAndArgumentRequirements( std::vector<AtomNumber> // } // } -void MultiReferenceBase::copyFrame( ReferenceConfiguration* frameToCopy ){ +void MultiReferenceBase::copyFrame( ReferenceConfiguration* frameToCopy ) { // Create a reference configuration of the appropriate type ReferenceConfiguration* mymsd=metricRegister().create<ReferenceConfiguration>( frameToCopy->getName() ); // Copy names of arguments and and indexes @@ -80,25 +80,25 @@ void MultiReferenceBase::copyFrame( ReferenceConfiguration* frameToCopy ){ // Copy weight mymsd->setWeight( frameToCopy->getWeight() ); // Easy bit - copy the frame - frames.push_back( mymsd ); + frames.push_back( mymsd ); // This resizes the low dim array resizeRestOfFrame(); } -void MultiReferenceBase::setWeights( const std::vector<double>& weights ){ - plumed_assert( weights.size()==frames.size() ); - for(unsigned i=0;i<weights.size();++i) frames[i]->setWeight( weights[i] ); +void MultiReferenceBase::setWeights( const std::vector<double>& weights ) { + plumed_assert( weights.size()==frames.size() ); + for(unsigned i=0; i<weights.size(); ++i) frames[i]->setWeight( weights[i] ); } -void MultiReferenceBase::calculateAllDistances( const Pbc& pbc, const std::vector<Value*> & vals, Communicator& comm, Matrix<double>& distances, const bool& squared ){ +void MultiReferenceBase::calculateAllDistances( const Pbc& pbc, const std::vector<Value*> & vals, Communicator& comm, Matrix<double>& distances, const bool& squared ) { distances=0.0; - unsigned k=0, size=comm.Get_size(), rank=comm.Get_rank(); - for(unsigned i=1;i<frames.size();++i){ - for(unsigned j=0;j<i;++j){ - if( (k++)%size!=rank ) continue; - distances(i,j) = distances(j,i) = distance( pbc, vals, frames[i], frames[j], squared ); - } + unsigned k=0, size=comm.Get_size(), rank=comm.Get_rank(); + for(unsigned i=1; i<frames.size(); ++i) { + for(unsigned j=0; j<i; ++j) { + if( (k++)%size!=rank ) continue; + distances(i,j) = distances(j,i) = distance( pbc, vals, frames[i], frames[j], squared ); + } } comm.Sum( distances ); } diff --git a/src/reference/MultiReferenceBase.h b/src/reference/MultiReferenceBase.h index 0c5b71c5f..3731ae07c 100644 --- a/src/reference/MultiReferenceBase.h +++ b/src/reference/MultiReferenceBase.h @@ -40,26 +40,26 @@ protected: std::vector<ReferenceConfiguration*> frames; /// Read something from the last frame template <class T> - void parse(const std::string& key, T& val ); + void parse(const std::string& key, T& val ); public: MultiReferenceBase( const std::string& type, const bool& checksoff ); /// Destructor deletes all polymorphic pointers virtual ~MultiReferenceBase(); /// Delete all the data in the reference object void clearFrames(); - virtual void clearRestOfData(){}; + virtual void clearRestOfData() {}; /// Read a frame from the input - void readFrame( PDB& pdb ); + void readFrame( PDB& pdb ); /// Find what is required of us from the reference frames void getAtomAndArgumentRequirements( std::vector<AtomNumber>& atoms, std::vector<std::string>& args ); /// Finish setup of frames // void setNumberOfAtomsAndArguments( const unsigned& natoms, const unsigned& nargs ); /// Do additional reading required by derived class - virtual void readRestOfFrame(){} + virtual void readRestOfFrame() {} /// Do additional resizing required by derived class - virtual void resizeRestOfFrame(){} + virtual void resizeRestOfFrame() {} /// Return the size of the frames vector - unsigned getNumberOfReferenceFrames() const ; + unsigned getNumberOfReferenceFrames() const ; /// Calculate the distance from one of the reference points double calcDistanceFromConfiguration( const unsigned& ifunc, const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& arg, ReferenceValuePack& myder, const bool& squared ) const ; @@ -68,7 +68,7 @@ public: /// Return a reference to all the reference frames std::vector<ReferenceConfiguration*>& getReferenceConfigurations(); /// Copy a reference configuration into the multi reference object - void copyFrame( ReferenceConfiguration* frameToCopy ); + void copyFrame( ReferenceConfiguration* frameToCopy ); /// Set the weight of the ith frame void setWeights( const std::vector<double>& ww ); /// Retrieve the weight of one of the frames @@ -78,37 +78,37 @@ public: }; template <class T> -void MultiReferenceBase::parse(const std::string& key, T& val ){ +void MultiReferenceBase::parse(const std::string& key, T& val ) { frames[frames.size()-1]->parse(key,val); } inline double MultiReferenceBase::calcDistanceFromConfiguration( const unsigned& ifunc, const std::vector<Vector>& pos, const Pbc& pbc, - const std::vector<Value*>& arg, ReferenceValuePack& myder, const bool& squared ) const { - return frames[ifunc]->calculate( pos, pbc, arg, myder, squared ); + const std::vector<Value*>& arg, ReferenceValuePack& myder, const bool& squared ) const { + return frames[ifunc]->calculate( pos, pbc, arg, myder, squared ); } inline unsigned MultiReferenceBase::getNumberOfReferenceFrames() const { - return frames.size(); + return frames.size(); } inline -double MultiReferenceBase::getWeight( const unsigned& ifram ) const { +double MultiReferenceBase::getWeight( const unsigned& ifram ) const { plumed_dbg_assert( ifram<frames.size() ); return frames[ifram]->getWeight(); } inline -ReferenceConfiguration* MultiReferenceBase::getFrame( const unsigned& iframe ){ - plumed_dbg_assert( iframe<frames.size() ); - return frames[iframe]; +ReferenceConfiguration* MultiReferenceBase::getFrame( const unsigned& iframe ) { + plumed_dbg_assert( iframe<frames.size() ); + return frames[iframe]; } inline -std::vector<ReferenceConfiguration*>& MultiReferenceBase::getReferenceConfigurations(){ +std::vector<ReferenceConfiguration*>& MultiReferenceBase::getReferenceConfigurations() { return frames; -} +} } #endif diff --git a/src/reference/NormalizedEuclideanDistance.cpp b/src/reference/NormalizedEuclideanDistance.cpp index 0fa8eb754..9b4d14a32 100644 --- a/src/reference/NormalizedEuclideanDistance.cpp +++ b/src/reference/NormalizedEuclideanDistance.cpp @@ -32,8 +32,8 @@ public: PLUMED_REGISTER_METRIC(NormalizedEuclideanDistance,"NORM-EUCLIDEAN") NormalizedEuclideanDistance::NormalizedEuclideanDistance( const ReferenceConfigurationOptions& ro ): -ReferenceConfiguration(ro), -ArgumentOnlyDistance(ro) + ReferenceConfiguration(ro), + ArgumentOnlyDistance(ro) { hasweights=true; } diff --git a/src/reference/OptimalRMSD.cpp b/src/reference/OptimalRMSD.cpp index 6d3ca828a..dc4d7f31b 100644 --- a/src/reference/OptimalRMSD.cpp +++ b/src/reference/OptimalRMSD.cpp @@ -24,7 +24,7 @@ #include "tools/Matrix.h" #include "tools/RMSD.h" -namespace PLMD{ +namespace PLMD { class OptimalRMSD : public RMSDBase { private: @@ -34,45 +34,45 @@ public: explicit OptimalRMSD(const ReferenceConfigurationOptions& ro); void read( const PDB& ); double calc( const std::vector<Vector>& pos, ReferenceValuePack& myder, const bool& squared ) const ; - bool pcaIsEnabledForThisReference(){ return true; } - void setupRMSDObject(){ myrmsd.clear(); myrmsd.set(getAlign(),getDisplace(),getReferencePositions(),"OPTIMAL"); } - void setupPCAStorage( ReferenceValuePack& mypack ){ - mypack.switchOnPCAOption(); - mypack.centeredpos.resize( getNumberOfAtoms() ); - mypack.displacement.resize( getNumberOfAtoms() ); - mypack.DRotDPos.resize(3,3); mypack.rot.resize(1); + bool pcaIsEnabledForThisReference() { return true; } + void setupRMSDObject() { myrmsd.clear(); myrmsd.set(getAlign(),getDisplace(),getReferencePositions(),"OPTIMAL"); } + void setupPCAStorage( ReferenceValuePack& mypack ) { + mypack.switchOnPCAOption(); + mypack.centeredpos.resize( getNumberOfAtoms() ); + mypack.displacement.resize( getNumberOfAtoms() ); + mypack.DRotDPos.resize(3,3); mypack.rot.resize(1); } - void extractAtomicDisplacement( const std::vector<Vector>& pos, const bool & anflag, std::vector<Vector>& direction ) const ; - double projectAtomicDisplacementOnVector( const std::vector<Vector>& vecs, const std::vector<Vector>& pos, ReferenceValuePack& mypack ) const ; + void extractAtomicDisplacement( const std::vector<Vector>& pos, const bool & anflag, std::vector<Vector>& direction ) const ; + double projectAtomicDisplacementOnVector( const std::vector<Vector>& vecs, const std::vector<Vector>& pos, ReferenceValuePack& mypack ) const ; }; PLUMED_REGISTER_METRIC(OptimalRMSD,"OPTIMAL") OptimalRMSD::OptimalRMSD(const ReferenceConfigurationOptions& ro ): -ReferenceConfiguration(ro), -RMSDBase(ro) + ReferenceConfiguration(ro), + RMSDBase(ro) { fast=ro.usingFastOption(); } -void OptimalRMSD::read( const PDB& pdb ){ - readReference( pdb ); setupRMSDObject(); +void OptimalRMSD::read( const PDB& pdb ) { + readReference( pdb ); setupRMSDObject(); } double OptimalRMSD::calc( const std::vector<Vector>& pos, ReferenceValuePack& myder, const bool& squared ) const { - double d; - if( myder.calcUsingPCAOption() ){ - std::vector<Vector> centeredreference( getNumberOfAtoms () ); - d=myrmsd.calc_PCAelements(pos,myder.getAtomVector(),myder.rot[0],myder.DRotDPos,myder.getAtomsDisplacementVector(),myder.centeredpos,centeredreference,squared); - unsigned nat = pos.size(); for(unsigned i=0;i<nat;++i) myder.getAtomsDisplacementVector()[i] -= getReferencePosition(i); - } else if( fast ){ - if( getAlign()==getDisplace() ) d=myrmsd.optimalAlignment<false,true>(getAlign(),getDisplace(),pos,getReferencePositions(),myder.getAtomVector(),squared); - else d=myrmsd.optimalAlignment<false,false>(getAlign(),getDisplace(),pos,getReferencePositions(),myder.getAtomVector(),squared); + double d; + if( myder.calcUsingPCAOption() ) { + std::vector<Vector> centeredreference( getNumberOfAtoms () ); + d=myrmsd.calc_PCAelements(pos,myder.getAtomVector(),myder.rot[0],myder.DRotDPos,myder.getAtomsDisplacementVector(),myder.centeredpos,centeredreference,squared); + unsigned nat = pos.size(); for(unsigned i=0; i<nat; ++i) myder.getAtomsDisplacementVector()[i] -= getReferencePosition(i); + } else if( fast ) { + if( getAlign()==getDisplace() ) d=myrmsd.optimalAlignment<false,true>(getAlign(),getDisplace(),pos,getReferencePositions(),myder.getAtomVector(),squared); + else d=myrmsd.optimalAlignment<false,false>(getAlign(),getDisplace(),pos,getReferencePositions(),myder.getAtomVector(),squared); } else { - if( getAlign()==getDisplace() ) d=myrmsd.optimalAlignment<true,true>(getAlign(),getDisplace(),pos,getReferencePositions(),myder.getAtomVector(),squared); - else d=myrmsd.optimalAlignment<true,false>(getAlign(),getDisplace(),pos,getReferencePositions(),myder.getAtomVector(),squared); + if( getAlign()==getDisplace() ) d=myrmsd.optimalAlignment<true,true>(getAlign(),getDisplace(),pos,getReferencePositions(),myder.getAtomVector(),squared); + else d=myrmsd.optimalAlignment<true,false>(getAlign(),getDisplace(),pos,getReferencePositions(),myder.getAtomVector(),squared); } - myder.clear(); for(unsigned i=0;i<pos.size();++i) myder.setAtomDerivatives( i, myder.getAtomVector()[i] ); + myder.clear(); for(unsigned i=0; i<pos.size(); ++i) myder.setAtomDerivatives( i, myder.getAtomVector()[i] ); if( !myder.updateComplete() ) myder.updateDynamicLists(); return d; } @@ -82,29 +82,29 @@ void OptimalRMSD::extractAtomicDisplacement( const std::vector<Vector>& pos, con std::vector<Vector> centeredreference( getNumberOfAtoms() ), centeredpos( getNumberOfAtoms() ), avector( getNumberOfAtoms() ); double d=myrmsd.calc_PCAelements(pos,avector,rot[0],DRotDPos,direction,centeredpos,centeredreference,true); unsigned nat = pos.size(); double scale=1.0; if( anflag ) scale = 1.0 / static_cast<double>( nat ); - for(unsigned i=0;i<nat;++i) direction[i] = scale*( direction[i] - getReferencePosition(i) ); + for(unsigned i=0; i<nat; ++i) direction[i] = scale*( direction[i] - getReferencePosition(i) ); } double OptimalRMSD::projectAtomicDisplacementOnVector( const std::vector<Vector>& vecs, const std::vector<Vector>& pos, ReferenceValuePack& mypack ) const { plumed_dbg_assert( mypack.calcUsingPCAOption() ); double proj=0.0; mypack.clear(); - for(unsigned i=0;i<pos.size();++i){ - proj += dotProduct( mypack.getAtomsDisplacementVector()[i] , vecs[i] ); + for(unsigned i=0; i<pos.size(); ++i) { + proj += dotProduct( mypack.getAtomsDisplacementVector()[i], vecs[i] ); } - for(unsigned a=0;a<3;a++){ - for(unsigned b=0;b<3;b++){ - for(unsigned iat=0;iat<getNumberOfAtoms();iat++){ - double tmp1=0.; - for(unsigned n=0;n<getNumberOfAtoms();n++) tmp1+=mypack.centeredpos[n][b]*vecs[n][a]; - mypack.addAtomDerivatives( iat, mypack.DRotDPos[a][b][iat]*tmp1 ); - } + for(unsigned a=0; a<3; a++) { + for(unsigned b=0; b<3; b++) { + for(unsigned iat=0; iat<getNumberOfAtoms(); iat++) { + double tmp1=0.; + for(unsigned n=0; n<getNumberOfAtoms(); n++) tmp1+=mypack.centeredpos[n][b]*vecs[n][a]; + mypack.addAtomDerivatives( iat, mypack.DRotDPos[a][b][iat]*tmp1 ); } + } } Tensor trot=mypack.rot[0].transpose(); Vector v1; v1.zero(); double prefactor = 1. / static_cast<double>( getNumberOfAtoms() ); - for(unsigned n=0;n<getNumberOfAtoms();n++) v1+=prefactor*matmul(trot,vecs[n]); - for(unsigned iat=0;iat<getNumberOfAtoms();iat++) mypack.addAtomDerivatives( iat, matmul(trot,vecs[iat])-v1 ); + for(unsigned n=0; n<getNumberOfAtoms(); n++) v1+=prefactor*matmul(trot,vecs[n]); + for(unsigned iat=0; iat<getNumberOfAtoms(); iat++) mypack.addAtomDerivatives( iat, matmul(trot,vecs[iat])-v1 ); if( !mypack.updateComplete() ) mypack.updateDynamicLists(); return proj; diff --git a/src/reference/PointWiseMapping.cpp b/src/reference/PointWiseMapping.cpp index b14a95083..cf3747ba6 100644 --- a/src/reference/PointWiseMapping.cpp +++ b/src/reference/PointWiseMapping.cpp @@ -26,78 +26,78 @@ namespace PLMD { PointWiseMapping::PointWiseMapping( const std::string& type, const bool& checksoff ): -MultiReferenceBase(type,checksoff) + MultiReferenceBase(type,checksoff) { ispath=false; } -void PointWiseMapping::setPropertyNames( const std::vector<std::string>& prop, const bool isp ){ +void PointWiseMapping::setPropertyNames( const std::vector<std::string>& prop, const bool isp ) { property.resize( prop.size() ); ispath=isp; - for(unsigned i=0;i<prop.size();++i) property[i]=prop[i]; + for(unsigned i=0; i<prop.size(); ++i) property[i]=prop[i]; } -void PointWiseMapping::readRestOfFrame(){ +void PointWiseMapping::readRestOfFrame() { Direction* tdir = dynamic_cast<Direction*>( getFrame( getNumberOfReferenceFrames() - 1 ) ); if( tdir ) plumed_merror("cannot use directions in mapping"); plumed_dbg_assert( property.size()>0 ); std::vector<double> labelvals; - if( !ispath ){ - labelvals.resize( property.size() ); - for(unsigned i=0;i<property.size();++i) parse( property[i], labelvals[i] ); + if( !ispath ) { + labelvals.resize( property.size() ); + for(unsigned i=0; i<property.size(); ++i) parse( property[i], labelvals[i] ); } else { - labelvals.resize(1); - labelvals[0]=static_cast<double>( frames.size() ); + labelvals.resize(1); + labelvals[0]=static_cast<double>( frames.size() ); } - low_dim.push_back( labelvals ); + low_dim.push_back( labelvals ); plumed_dbg_assert( low_dim.size()==getNumberOfReferenceFrames() ); } -void PointWiseMapping::clearRestOfData(){ +void PointWiseMapping::clearRestOfData() { low_dim.resize(0); -} +} -void PointWiseMapping::resizeRestOfFrame(){ +void PointWiseMapping::resizeRestOfFrame() { plumed_dbg_assert( property.size()>0 ); std::vector<double> labelvals( property.size() ); low_dim.push_back( labelvals ); plumed_dbg_assert( low_dim.size()==getNumberOfReferenceFrames() ); } -void PointWiseMapping::duplicateFrameList(){ +void PointWiseMapping::duplicateFrameList() { unsigned nframes=frames.size(); - for(unsigned i=0;i<nframes;++i){ - frames.push_back( new FakeFrame( ReferenceConfigurationOptions("fake") ) ); + for(unsigned i=0; i<nframes; ++i) { + frames.push_back( new FakeFrame( ReferenceConfigurationOptions("fake") ) ); } } unsigned PointWiseMapping::getPropertyIndex( const std::string& name ) const { - for(unsigned i=0;i<property.size();++i){ - if( name==property[i] ) return i; + for(unsigned i=0; i<property.size(); ++i) { + if( name==property[i] ) return i; } plumed_merror("no property with name " + name + " found"); return 0; } -void PointWiseMapping::print( const std::string& method, const double & time, OFile& afile, - const std::string& fmt, const double& lunits ){ +void PointWiseMapping::print( const std::string& method, const double & time, OFile& afile, + const std::string& fmt, const double& lunits ) { std::string descr2, descr="DESCRIPTION: results from %s analysis performed at time " + fmt +"\n"; afile.printf(descr.c_str(), method.c_str(), time ); - if(fmt.find("-")!=std::string::npos){ - descr="REMARK WEIGHT=" + fmt + " %s=" + fmt + " "; descr2="%s=" + fmt; + if(fmt.find("-")!=std::string::npos) { + descr="REMARK WEIGHT=" + fmt + " %s=" + fmt + " "; descr2="%s=" + fmt; } else { - // This ensures numbers are left justified (i.e. next to the equals sign - std::size_t psign=fmt.find("%"); - plumed_assert( psign!=std::string::npos ); - descr="REMARK WEIGHT=%-" + fmt.substr(psign+1) + " %s=%-" + fmt.substr(psign+1) + " "; - descr2="%s=%-" + fmt.substr(psign+1); + // This ensures numbers are left justified (i.e. next to the equals sign + std::size_t psign=fmt.find("%"); + plumed_assert( psign!=std::string::npos ); + descr="REMARK WEIGHT=%-" + fmt.substr(psign+1) + " %s=%-" + fmt.substr(psign+1) + " "; + descr2="%s=%-" + fmt.substr(psign+1); } - for(unsigned i=0;i<frames.size();++i){ - afile.printf(descr.c_str(), frames[i]->getWeight(), property[0].c_str(), low_dim[i][0] ); - for(unsigned j=1;j<property.size();++j) afile.printf(descr2.c_str(), property[j].c_str(), low_dim[i][j]); - afile.printf("\n"); - frames[i]->print( afile, fmt, lunits ); + for(unsigned i=0; i<frames.size(); ++i) { + afile.printf(descr.c_str(), frames[i]->getWeight(), property[0].c_str(), low_dim[i][0] ); + for(unsigned j=1; j<property.size(); ++j) afile.printf(descr2.c_str(), property[j].c_str(), low_dim[i][j]); + afile.printf("\n"); + frames[i]->print( afile, fmt, lunits ); } -} +} } diff --git a/src/reference/PointWiseMapping.h b/src/reference/PointWiseMapping.h index 1345e62fc..a530d3492 100644 --- a/src/reference/PointWiseMapping.h +++ b/src/reference/PointWiseMapping.h @@ -35,7 +35,7 @@ private: /// The names of the projection coordinates std::vector<std::string> property; /// These are where the reference configurations should be projected - std::vector< std::vector<double> > low_dim; + std::vector< std::vector<double> > low_dim; public: PointWiseMapping( const std::string& type, const bool& checksoff ); /// Set the names of the low dimensional properties @@ -44,11 +44,11 @@ public: bool mappingNeedsSetup() const; /// Delete the low dimensional projections void clearRestOfData(); -/// Read in the data from a file +/// Read in the data from a file void readRestOfFrame(); /// Resize everything else from a file void resizeRestOfFrame(); -/// Make a second copy of the frame list +/// Make a second copy of the frame list void duplicateFrameList(); /// Get the number of points we are mapping into the lower dimensional space unsigned getNumberOfMappedPoints() const ; @@ -71,7 +71,7 @@ public: /// Get a pointer to the matrix of pairwise distances Matrix<double>& modifyDmat(); /// Print out the low dimensional mapping - void print( const std::string& method, const double & time, OFile& afile, + void print( const std::string& method, const double & time, OFile& afile, const std::string& fmt, const double& lunits ); /// Get the low dimensional embedding coordinate double getProjectionCoordinate( const unsigned& iframe, const unsigned& jcoord ) const ; @@ -86,7 +86,7 @@ bool PointWiseMapping::mappingNeedsSetup() const { } inline -void PointWiseMapping::copyFrameDerivatives( const unsigned& from, const unsigned& to ){ +void PointWiseMapping::copyFrameDerivatives( const unsigned& from, const unsigned& to ) { plumed_dbg_assert( to>=frames.size()/2 && from<frames.size()/2 ); frames[to]->copyDerivatives( frames[from] ); } @@ -117,7 +117,7 @@ double PointWiseMapping::getPropertyValue( const unsigned& iframe, const unsigne // Vector PointWiseMapping::getAtomDerivatives( const unsigned& iframe, const unsigned& jatom ){ // return frames[iframe]->getAtomDerivative(jatom); // } -// +// // inline // bool PointWiseMapping::getVirial( const unsigned& iframe, Tensor& vir ){ // return frames[iframe]->getVirial( vir ); @@ -129,7 +129,7 @@ double PointWiseMapping::getPropertyValue( const unsigned& iframe, const unsigne // } inline -Matrix<double>& PointWiseMapping::modifyDmat(){ +Matrix<double>& PointWiseMapping::modifyDmat() { if( dmat.nrows()!=frames.size() || dmat.ncols()!=frames.size() ) dmat.resize( frames.size(), frames.size() ); return dmat; } @@ -141,10 +141,10 @@ double PointWiseMapping::getProjectionCoordinate( const unsigned& iframe, const } inline -void PointWiseMapping::setProjectionCoordinate( const unsigned& iframe, const unsigned& jcoord, const double& coord ){ +void PointWiseMapping::setProjectionCoordinate( const unsigned& iframe, const unsigned& jcoord, const double& coord ) { plumed_dbg_assert( iframe<frames.size() && jcoord<property.size() ); low_dim[iframe][jcoord]=coord; -} +} } #endif diff --git a/src/reference/RMSDBase.cpp b/src/reference/RMSDBase.cpp index 05a82e1ff..68b30e099 100644 --- a/src/reference/RMSDBase.cpp +++ b/src/reference/RMSDBase.cpp @@ -21,18 +21,18 @@ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ #include "RMSDBase.h" -namespace PLMD{ +namespace PLMD { RMSDBase::RMSDBase( const ReferenceConfigurationOptions& ro ): -ReferenceConfiguration(ro), -SingleDomainRMSD(ro) + ReferenceConfiguration(ro), + SingleDomainRMSD(ro) { } double RMSDBase::calculate( const std::vector<Vector>& pos, ReferenceValuePack& myder, const bool& squared ) const { -// clearDerivatives(); +// clearDerivatives(); return calc( pos, myder, squared ); -} +} double RMSDBase::calc( const std::vector<Vector>& pos, const Pbc& pbc, ReferenceValuePack& myder, const bool& squared ) const { plumed_dbg_assert( pos.size()==getNumberOfAtoms() ); diff --git a/src/reference/RMSDBase.h b/src/reference/RMSDBase.h index 9a59d1f1c..e1fb621e2 100644 --- a/src/reference/RMSDBase.h +++ b/src/reference/RMSDBase.h @@ -36,7 +36,7 @@ class RMSDBase : public SingleDomainRMSD { public: explicit RMSDBase( const ReferenceConfigurationOptions& ro ); double calc( const std::vector<Vector>& pos, const Pbc& pbc, ReferenceValuePack& myder, const bool& squared ) const; - double calculate( const std::vector<Vector>& pos, ReferenceValuePack& myder, const bool& squared ) const ; + double calculate( const std::vector<Vector>& pos, ReferenceValuePack& myder, const bool& squared ) const ; virtual double calc( const std::vector<Vector>& pos, ReferenceValuePack& myder, const bool& squared ) const=0; }; diff --git a/src/reference/ReferenceArguments.cpp b/src/reference/ReferenceArguments.cpp index 20c6cb5b5..e051f1d7b 100644 --- a/src/reference/ReferenceArguments.cpp +++ b/src/reference/ReferenceArguments.cpp @@ -27,204 +27,204 @@ namespace PLMD { ReferenceArguments::ReferenceArguments( const ReferenceConfigurationOptions& ro ): -ReferenceConfiguration(ro), -hasweights(false), -hasmetric(false) + ReferenceConfiguration(ro), + hasweights(false), + hasmetric(false) { } -void ReferenceArguments::readArgumentsFromPDB( const PDB& pdb ){ +void ReferenceArguments::readArgumentsFromPDB( const PDB& pdb ) { ReferenceAtoms* aref=dynamic_cast<ReferenceAtoms*>( this ); if( !aref ) parseVector( "ARG", arg_names ); else parseVector( "ARG", arg_names, true ); reference_args.resize( arg_names.size() ); - for(unsigned i=0;i<arg_names.size();++i) parse( arg_names[i], reference_args[i] ); - - if( hasweights ){ - plumed_massert( !hasmetric, "should not have weights if we are using metric"); - weights.resize( arg_names.size() ); sqrtweight.resize( arg_names.size() ); - for(unsigned i=0;i<reference_args.size();++i){ - parse( "sigma_" + arg_names[i], weights[i] ); - sqrtweight[i] = sqrt( weights[i] ); - } - } else if( hasmetric ){ - plumed_massert( !hasweights, "should not have weights if we are using metric"); - double thissig; metric.resize( arg_names.size(), arg_names.size() ); - for(unsigned i=0;i<reference_args.size();++i){ - for(unsigned j=i;j<reference_args.size();++j){ - parse( "sigma_" + arg_names[i] + "_" + arg_names[j], thissig ); - metric(i,j)=metric(j,i)=thissig; - } + for(unsigned i=0; i<arg_names.size(); ++i) parse( arg_names[i], reference_args[i] ); + + if( hasweights ) { + plumed_massert( !hasmetric, "should not have weights if we are using metric"); + weights.resize( arg_names.size() ); sqrtweight.resize( arg_names.size() ); + for(unsigned i=0; i<reference_args.size(); ++i) { + parse( "sigma_" + arg_names[i], weights[i] ); + sqrtweight[i] = sqrt( weights[i] ); + } + } else if( hasmetric ) { + plumed_massert( !hasweights, "should not have weights if we are using metric"); + double thissig; metric.resize( arg_names.size(), arg_names.size() ); + for(unsigned i=0; i<reference_args.size(); ++i) { + for(unsigned j=i; j<reference_args.size(); ++j) { + parse( "sigma_" + arg_names[i] + "_" + arg_names[j], thissig ); + metric(i,j)=metric(j,i)=thissig; } + } } else { - weights.resize( arg_names.size() ); sqrtweight.resize( arg_names.size() ); - for(unsigned i=0;i<weights.size();++i) sqrtweight[i]=weights[i]=1.0; + weights.resize( arg_names.size() ); sqrtweight.resize( arg_names.size() ); + for(unsigned i=0; i<weights.size(); ++i) sqrtweight[i]=weights[i]=1.0; } } -void ReferenceArguments::setArgumentNames( const std::vector<std::string>& arg_vals ){ - reference_args.resize( arg_vals.size() ); - arg_names.resize( arg_vals.size() ); +void ReferenceArguments::setArgumentNames( const std::vector<std::string>& arg_vals ) { + reference_args.resize( arg_vals.size() ); + arg_names.resize( arg_vals.size() ); arg_der_index.resize( arg_vals.size() ); - for(unsigned i=0;i<arg_vals.size();++i){ - arg_names[i]=arg_vals[i]; arg_der_index[i]=i; + for(unsigned i=0; i<arg_vals.size(); ++i) { + arg_names[i]=arg_vals[i]; arg_der_index[i]=i; } if( hasmetric ) metric.resize( arg_vals.size(), arg_vals.size() ); else weights.resize( arg_vals.size() ); } -void ReferenceArguments::setReferenceArguments( const std::vector<double>& arg_vals, const std::vector<double>& sigma ){ +void ReferenceArguments::setReferenceArguments( const std::vector<double>& arg_vals, const std::vector<double>& sigma ) { moveReferenceArguments( arg_vals ); - - if( hasmetric ){ - unsigned k=0; - for(unsigned i=0;i<reference_args.size();++i){ - for(unsigned j=i;j<reference_args.size();++j){ - metric(i,j)=metric(j,i)=sigma[k]; k++; - } - } - plumed_assert( k==sigma.size() ); + + if( hasmetric ) { + unsigned k=0; + for(unsigned i=0; i<reference_args.size(); ++i) { + for(unsigned j=i; j<reference_args.size(); ++j) { + metric(i,j)=metric(j,i)=sigma[k]; k++; + } + } + plumed_assert( k==sigma.size() ); } else { - plumed_assert( reference_args.size()==sigma.size() ); - for(unsigned i=0;i<reference_args.size();++i) weights[i]=sigma[i]; - } + plumed_assert( reference_args.size()==sigma.size() ); + for(unsigned i=0; i<reference_args.size(); ++i) weights[i]=sigma[i]; + } } -void ReferenceArguments::moveReferenceArguments( const std::vector<double>& arg_vals ){ +void ReferenceArguments::moveReferenceArguments( const std::vector<double>& arg_vals ) { plumed_dbg_assert( reference_args.size()==arg_vals.size() ); - for(unsigned i=0;i<arg_vals.size();++i) reference_args[i]=arg_vals[i]; + for(unsigned i=0; i<arg_vals.size(); ++i) reference_args[i]=arg_vals[i]; } -void ReferenceArguments::getArgumentRequests( std::vector<std::string>& argout, bool disable_checks ){ +void ReferenceArguments::getArgumentRequests( std::vector<std::string>& argout, bool disable_checks ) { arg_der_index.resize( arg_names.size() ); - if( argout.size()==0 ){ - for(unsigned i=0;i<arg_names.size();++i){ - argout.push_back( arg_names[i] ); - arg_der_index[i]=i; - } + if( argout.size()==0 ) { + for(unsigned i=0; i<arg_names.size(); ++i) { + argout.push_back( arg_names[i] ); + arg_der_index[i]=i; + } } else { - if(!disable_checks){ - if( arg_names.size()!=argout.size() ) error("mismatched numbers of arguments in pdb frames"); - } - for(unsigned i=0;i<arg_names.size();++i){ - bool found=false; - if(!disable_checks){ - if( argout[i]!=arg_names[i] ) error("found mismatched arguments in pdb frames"); - arg_der_index[i]=i; - } else { - for(unsigned j=0;j<arg_names.size();++j){ - if( argout[j]==arg_names[i] ){ found=true; arg_der_index[i]=j; break; } - } - if( !found ){ - arg_der_index[i]=argout.size(); argout.push_back( arg_names[i] ); - } - } + if(!disable_checks) { + if( arg_names.size()!=argout.size() ) error("mismatched numbers of arguments in pdb frames"); + } + for(unsigned i=0; i<arg_names.size(); ++i) { + bool found=false; + if(!disable_checks) { + if( argout[i]!=arg_names[i] ) error("found mismatched arguments in pdb frames"); + arg_der_index[i]=i; + } else { + for(unsigned j=0; j<arg_names.size(); ++j) { + if( argout[j]==arg_names[i] ) { found=true; arg_der_index[i]=j; break; } + } + if( !found ) { + arg_der_index[i]=argout.size(); argout.push_back( arg_names[i] ); + } } + } } } void ReferenceArguments::printArguments( OFile& ofile, const std::string& fmt ) const { - if( arg_names.size()>0 ){ - ofile.printf("REMARK ARG=%s", arg_names[0].c_str() ); - for(unsigned i=1;i<arg_names.size();++i) ofile.printf(",%s", arg_names[i].c_str() ); - ofile.printf("\n"); - - ofile.printf("REMARK "); - std::string descr2; - if(fmt.find("-")!=std::string::npos){ - descr2="%s=" + fmt + " "; - } else { - // This ensures numbers are left justified (i.e. next to the equals sign - std::size_t psign=fmt.find("%"); - plumed_assert( psign!=std::string::npos ); - descr2="%s=%-" + fmt.substr(psign+1) + " "; - } - for(unsigned i=0;i<arg_names.size();++i) ofile.printf( descr2.c_str(),arg_names[i].c_str(), reference_args[i] ); - ofile.printf("\n"); + if( arg_names.size()>0 ) { + ofile.printf("REMARK ARG=%s", arg_names[0].c_str() ); + for(unsigned i=1; i<arg_names.size(); ++i) ofile.printf(",%s", arg_names[i].c_str() ); + ofile.printf("\n"); + + ofile.printf("REMARK "); + std::string descr2; + if(fmt.find("-")!=std::string::npos) { + descr2="%s=" + fmt + " "; + } else { + // This ensures numbers are left justified (i.e. next to the equals sign + std::size_t psign=fmt.find("%"); + plumed_assert( psign!=std::string::npos ); + descr2="%s=%-" + fmt.substr(psign+1) + " "; + } + for(unsigned i=0; i<arg_names.size(); ++i) ofile.printf( descr2.c_str(),arg_names[i].c_str(), reference_args[i] ); + ofile.printf("\n"); } // Missing print out of metrics } -const std::vector<double>& ReferenceArguments::getReferenceMetric(){ - if( hasmetric ){ - unsigned ntot=(reference_args.size() / 2 )*(reference_args.size()+1); - if( trig_metric.size()!=ntot ) trig_metric.resize( ntot ); - unsigned k=0; - for(unsigned i=0;i<reference_args.size();++i){ - for(unsigned j=i;j<reference_args.size();++j){ - plumed_dbg_assert( fabs( metric(i,j)-metric(j,i) ) < epsilon ); - trig_metric[k]=metric(i,j); k++; - } - } +const std::vector<double>& ReferenceArguments::getReferenceMetric() { + if( hasmetric ) { + unsigned ntot=(reference_args.size() / 2 )*(reference_args.size()+1); + if( trig_metric.size()!=ntot ) trig_metric.resize( ntot ); + unsigned k=0; + for(unsigned i=0; i<reference_args.size(); ++i) { + for(unsigned j=i; j<reference_args.size(); ++j) { + plumed_dbg_assert( fabs( metric(i,j)-metric(j,i) ) < epsilon ); + trig_metric[k]=metric(i,j); k++; + } + } } else { if( trig_metric.size()!=reference_args.size() ) trig_metric.resize( reference_args.size() ); - for(unsigned i=0;i<reference_args.size();++i) trig_metric[i]=weights[i]; + for(unsigned i=0; i<reference_args.size(); ++i) trig_metric[i]=weights[i]; } return trig_metric; } -double ReferenceArguments::calculateArgumentDistance( const std::vector<Value*> & vals, const std::vector<double>& arg, - ReferenceValuePack& myder, const bool& squared ) const { +double ReferenceArguments::calculateArgumentDistance( const std::vector<Value*> & vals, const std::vector<double>& arg, + ReferenceValuePack& myder, const bool& squared ) const { double r=0; std::vector<double> arg_ders( vals.size() ); - if( hasmetric ){ - for(unsigned i=0;i<reference_args.size();++i){ - unsigned ik=arg_der_index[i]; arg_ders[ ik ]=0; - double dp_i=vals[ik]->difference( reference_args[i], arg[ik] ); - for(unsigned j=0;j<reference_args.size();++j){ - double dp_j; - unsigned jk=arg_der_index[j]; - if(i==j) dp_j=dp_i; - else dp_j=vals[jk]->difference( reference_args[j], arg[jk] ); - - arg_ders[ ik ]+=2.0*metric(i,j)*dp_j; // Factor of two for off diagonal terms as you have terms from ij and ji - r+=dp_i*dp_j*metric(i,j); - } + if( hasmetric ) { + for(unsigned i=0; i<reference_args.size(); ++i) { + unsigned ik=arg_der_index[i]; arg_ders[ ik ]=0; + double dp_i=vals[ik]->difference( reference_args[i], arg[ik] ); + for(unsigned j=0; j<reference_args.size(); ++j) { + double dp_j; + unsigned jk=arg_der_index[j]; + if(i==j) dp_j=dp_i; + else dp_j=vals[jk]->difference( reference_args[j], arg[jk] ); + + arg_ders[ ik ]+=2.0*metric(i,j)*dp_j; // Factor of two for off diagonal terms as you have terms from ij and ji + r+=dp_i*dp_j*metric(i,j); } + } } else { - for(unsigned i=0;i<reference_args.size();++i){ - unsigned ik=arg_der_index[i]; - double dp_i=vals[ik]->difference( reference_args[i], arg[ik] ); - r+=weights[i]*dp_i*dp_i; arg_ders[ik]=2.0*weights[i]*dp_i; - } + for(unsigned i=0; i<reference_args.size(); ++i) { + unsigned ik=arg_der_index[i]; + double dp_i=vals[ik]->difference( reference_args[i], arg[ik] ); + r+=weights[i]*dp_i*dp_i; arg_ders[ik]=2.0*weights[i]*dp_i; + } } - if(!squared){ - r=sqrt(r); double ir=1.0/(2.0*r); - for(unsigned i=0;i<arg_ders.size();++i) myder.setArgumentDerivatives( i, arg_ders[i]*ir ); + if(!squared) { + r=sqrt(r); double ir=1.0/(2.0*r); + for(unsigned i=0; i<arg_ders.size(); ++i) myder.setArgumentDerivatives( i, arg_ders[i]*ir ); } else { - for(unsigned i=0;i<arg_ders.size();++i) myder.setArgumentDerivatives( i, arg_ders[i] ); + for(unsigned i=0; i<arg_ders.size(); ++i) myder.setArgumentDerivatives( i, arg_ders[i] ); } return r; } void ReferenceArguments::extractArgumentDisplacement( const std::vector<Value*>& vals, const std::vector<double>& arg, std::vector<double>& dirout ) const { - if( hasmetric ){ - plumed_error(); + if( hasmetric ) { + plumed_error(); } else { - for(unsigned j=0;j<reference_args.size();++j){ - unsigned jk=arg_der_index[j]; dirout[jk]=sqrtweight[j]*vals[jk]->difference( reference_args[j], arg[jk] ); - } + for(unsigned j=0; j<reference_args.size(); ++j) { + unsigned jk=arg_der_index[j]; dirout[jk]=sqrtweight[j]*vals[jk]->difference( reference_args[j], arg[jk] ); + } } } double ReferenceArguments::projectArgDisplacementOnVector( const std::vector<double>& eigv, const std::vector<Value*>& vals, const std::vector<double>& arg, ReferenceValuePack& mypack ) const { - if( hasmetric ){ - plumed_error(); + if( hasmetric ) { + plumed_error(); } else { - double proj=0; - for(unsigned j=0;j<reference_args.size();++j){ - unsigned jk=arg_der_index[j]; - proj += eigv[j]*sqrtweight[j]*vals[jk]->difference( reference_args[j], arg[jk] ); - mypack.setArgumentDerivatives( jk, eigv[j]*sqrtweight[j] ); - } - return proj; + double proj=0; + for(unsigned j=0; j<reference_args.size(); ++j) { + unsigned jk=arg_der_index[j]; + proj += eigv[j]*sqrtweight[j]*vals[jk]->difference( reference_args[j], arg[jk] ); + mypack.setArgumentDerivatives( jk, eigv[j]*sqrtweight[j] ); + } + return proj; } } -void ReferenceArguments::displaceReferenceArguments( const double& weight, const std::vector<double>& displace ){ +void ReferenceArguments::displaceReferenceArguments( const double& weight, const std::vector<double>& displace ) { plumed_dbg_assert( displace.size()==getNumberOfReferenceArguments() ); - for(unsigned i=0;i<displace.size();++i) reference_args[i] += weight*displace[i]; + for(unsigned i=0; i<displace.size(); ++i) reference_args[i] += weight*displace[i]; } } diff --git a/src/reference/ReferenceArguments.h b/src/reference/ReferenceArguments.h index 92b32802c..6d1fc0e00 100644 --- a/src/reference/ReferenceArguments.h +++ b/src/reference/ReferenceArguments.h @@ -29,22 +29,22 @@ namespace PLMD { /// \ingroup TOOLBOX /// In many applications (e.g. paths, fields, property maps) it is necessary to calculate -/// the distance between two configurations. These distances can be calculated in a variety of +/// the distance between two configurations. These distances can be calculated in a variety of /// different ways. For instance, one can assert that the distance between the two configuration /// is the distance one would have to move all the atoms to transform configuration 1 into configuration /// 2. Alternatively, one could calculate the values of a large set of collective coordinates in the two -/// configurations and then calculate the Euclidean distances between these two points in the resulting -/// high-dimensional vector space. Lastly, one can combine these two forms of distance calculation to calculate +/// configurations and then calculate the Euclidean distances between these two points in the resulting +/// high-dimensional vector space. Lastly, one can combine these two forms of distance calculation to calculate /// a hybrid distance. Plumed allows one to use all these forms of distance calculations and also to implement /// new forms of distance. You should inherit from this class if your distance involves reference colvar values. -/// This class and \ref PLMD::ReferenceAtoms mirror the functionalities in \ref PLMD::ActionWithArguments and -/// \ref PLMD::ActionAtomistic respectively but for distances. +/// This class and \ref PLMD::ReferenceAtoms mirror the functionalities in \ref PLMD::ActionWithArguments and +/// \ref PLMD::ActionAtomistic respectively but for distances. class ReferenceArguments : virtual public ReferenceConfiguration { -friend class Direction; -friend class ReferenceConfiguration; + friend class Direction; + friend class ReferenceConfiguration; private: /// The weights for normed euclidean distance std::vector<double> weights, sqrtweight; @@ -60,7 +60,7 @@ private: protected: /// Are we reading weights from input bool hasweights; -/// Are we calculating a Malanobius distance +/// Are we calculating a Malanobius distance bool hasmetric; /// Read in the atoms from the pdb file void readArgumentsFromPDB( const PDB& pdb ); @@ -70,7 +70,7 @@ public: explicit ReferenceArguments( const ReferenceConfigurationOptions& ro ); /// Get the number of reference arguments unsigned getNumberOfReferenceArguments() const ; -/// Get the arguments required +/// Get the arguments required void getArgumentRequests( std::vector<std::string>&, bool disable_checks=false ); /// Set the names of the arguments void setArgumentNames( const std::vector<std::string>& arg_vals ); @@ -110,7 +110,7 @@ const std::vector<double>& ReferenceArguments::getReferenceArguments() const { } inline -const std::vector<std::string>& ReferenceArguments::getArgumentNames(){ +const std::vector<std::string>& ReferenceArguments::getArgumentNames() { return arg_names; } diff --git a/src/reference/ReferenceAtoms.cpp b/src/reference/ReferenceAtoms.cpp index e2d2ad05e..7120786f3 100644 --- a/src/reference/ReferenceAtoms.cpp +++ b/src/reference/ReferenceAtoms.cpp @@ -26,100 +26,100 @@ namespace PLMD { ReferenceAtoms::ReferenceAtoms( const ReferenceConfigurationOptions& ro ): -ReferenceConfiguration(ro), -checks_were_disabled(false) + ReferenceConfiguration(ro), + checks_were_disabled(false) { } -void ReferenceAtoms::readAtomsFromPDB( const PDB& pdb, const bool allowblocks ){ - if( !allowblocks && pdb.getNumberOfAtomBlocks()!=1 ) error("found multi-atom-block pdb format but expecting only one block of atoms"); +void ReferenceAtoms::readAtomsFromPDB( const PDB& pdb, const bool allowblocks ) { + if( !allowblocks && pdb.getNumberOfAtomBlocks()!=1 ) error("found multi-atom-block pdb format but expecting only one block of atoms"); - for(unsigned i=0;i<pdb.size();++i){ - indices.push_back( pdb.getAtomNumbers()[i] ); reference_atoms.push_back( pdb.getPositions()[i] ); - align.push_back( pdb.getOccupancy()[i] ); displace.push_back( pdb.getBeta()[i] ); + for(unsigned i=0; i<pdb.size(); ++i) { + indices.push_back( pdb.getAtomNumbers()[i] ); reference_atoms.push_back( pdb.getPositions()[i] ); + align.push_back( pdb.getOccupancy()[i] ); displace.push_back( pdb.getBeta()[i] ); } atom_der_index.resize( reference_atoms.size() ); } -void ReferenceAtoms::setAtomNumbers( const std::vector<AtomNumber>& numbers ){ +void ReferenceAtoms::setAtomNumbers( const std::vector<AtomNumber>& numbers ) { reference_atoms.resize( numbers.size() ); align.resize( numbers.size() ); displace.resize( numbers.size() ); atom_der_index.resize( numbers.size() ); indices.resize( numbers.size() ); - for(unsigned i=0;i<numbers.size();++i){ - indices[i]=numbers[i]; atom_der_index[i]=i; + for(unsigned i=0; i<numbers.size(); ++i) { + indices[i]=numbers[i]; atom_der_index[i]=i; } } void ReferenceAtoms::printAtoms( OFile& ofile, const double& lunits ) const { plumed_assert( indices.size()==reference_atoms.size() && align.size()==reference_atoms.size() && displace.size()==reference_atoms.size() ); - for(unsigned i=0;i<reference_atoms.size();++i){ - ofile.printf("ATOM %4d X RES %4u %8.3f%8.3f%8.3f%6.2f%6.2f\n", - indices[i].serial(), i, - lunits*reference_atoms[i][0], lunits*reference_atoms[i][1], lunits*reference_atoms[i][2], - align[i], displace[i] ); + for(unsigned i=0; i<reference_atoms.size(); ++i) { + ofile.printf("ATOM %4d X RES %4u %8.3f%8.3f%8.3f%6.2f%6.2f\n", + indices[i].serial(), i, + lunits*reference_atoms[i][0], lunits*reference_atoms[i][1], lunits*reference_atoms[i][2], + align[i], displace[i] ); } } -bool ReferenceAtoms::parseAtomList( const std::string& key, std::vector<unsigned>& numbers ){ +bool ReferenceAtoms::parseAtomList( const std::string& key, std::vector<unsigned>& numbers ) { plumed_assert( numbers.size()==0 ); - std::vector<std::string> strings; + std::vector<std::string> strings; if( !parseVector(key,strings,true) ) return false; - Tools::interpretRanges(strings); - - numbers.resize( strings.size() ); - for(unsigned i=0;i<strings.size();++i){ - AtomNumber atom; - if( !Tools::convert(strings[i],atom ) ) error("could not convert " + strings[i] + " into atom number"); - - bool found=false; - for(unsigned j=0;j<indices.size();++j){ - if( atom==indices[j] ){ found=true; numbers[i]=j; break; } - } - if(!found) error("atom labelled " + strings[i] + " is not present in pdb input file"); + Tools::interpretRanges(strings); + + numbers.resize( strings.size() ); + for(unsigned i=0; i<strings.size(); ++i) { + AtomNumber atom; + if( !Tools::convert(strings[i],atom ) ) error("could not convert " + strings[i] + " into atom number"); + + bool found=false; + for(unsigned j=0; j<indices.size(); ++j) { + if( atom==indices[j] ) { found=true; numbers[i]=j; break; } + } + if(!found) error("atom labelled " + strings[i] + " is not present in pdb input file"); } return true; } -void ReferenceAtoms::getAtomRequests( std::vector<AtomNumber>& numbers, bool disable_checks ){ +void ReferenceAtoms::getAtomRequests( std::vector<AtomNumber>& numbers, bool disable_checks ) { singleDomainRequests(numbers,disable_checks); } -void ReferenceAtoms::singleDomainRequests( std::vector<AtomNumber>& numbers, bool disable_checks ){ +void ReferenceAtoms::singleDomainRequests( std::vector<AtomNumber>& numbers, bool disable_checks ) { checks_were_disabled=disable_checks; atom_der_index.resize( indices.size() ); - if( numbers.size()==0 ){ - for(unsigned i=0;i<indices.size();++i){ - numbers.push_back( indices[i] ); - atom_der_index[i]=i; - } + if( numbers.size()==0 ) { + for(unsigned i=0; i<indices.size(); ++i) { + numbers.push_back( indices[i] ); + atom_der_index[i]=i; + } } else { - if(!disable_checks){ - if( numbers.size()!=indices.size() ) error("mismatched numbers of atoms in pdb frames"); - } - - bool found; - for(unsigned i=0;i<indices.size();++i){ - found=false; - if(!disable_checks){ - if( indices[i]!=numbers[i] ) error("found mismatched reference atoms in pdb frames"); - atom_der_index[i]=i; - } else { - for(unsigned j=0;j<numbers.size();++j){ - if( indices[i]==numbers[j] ){ found=true; atom_der_index[i]=j; break; } - } - if( !found ){ - atom_der_index[i]=numbers.size(); numbers.push_back( indices[i] ); - } - } + if(!disable_checks) { + if( numbers.size()!=indices.size() ) error("mismatched numbers of atoms in pdb frames"); + } + + bool found; + for(unsigned i=0; i<indices.size(); ++i) { + found=false; + if(!disable_checks) { + if( indices[i]!=numbers[i] ) error("found mismatched reference atoms in pdb frames"); + atom_der_index[i]=i; + } else { + for(unsigned j=0; j<numbers.size(); ++j) { + if( indices[i]==numbers[j] ) { found=true; atom_der_index[i]=j; break; } + } + if( !found ) { + atom_der_index[i]=numbers.size(); numbers.push_back( indices[i] ); + } } + } } } -void ReferenceAtoms::displaceReferenceAtoms( const double& weight, const std::vector<Vector>& dir ){ +void ReferenceAtoms::displaceReferenceAtoms( const double& weight, const std::vector<Vector>& dir ) { plumed_dbg_assert( dir.size()==reference_atoms.size() ); - for(unsigned i=0;i<dir.size();++i) reference_atoms[i] += weight*dir[i]; + for(unsigned i=0; i<dir.size(); ++i) reference_atoms[i] += weight*dir[i]; } } diff --git a/src/reference/ReferenceAtoms.h b/src/reference/ReferenceAtoms.h index cf17924ca..045171f64 100644 --- a/src/reference/ReferenceAtoms.h +++ b/src/reference/ReferenceAtoms.h @@ -30,23 +30,23 @@ class Pbc; /// \ingroup TOOLBOX /// In many applications (e.g. paths, fields, property maps) it is necessary to calculate -/// the distance between two configurations. These distances can be calculated in a variety of +/// the distance between two configurations. These distances can be calculated in a variety of /// different ways. For instance, one can assert that the distance between the two configuration /// is the distance one would have to move all the atoms to transform configuration 1 into configuration /// 2. Alternatively, one could calculate the values of a large set of collective coordinates in the two -/// configurations and then calculate the Euclidean distances between these two points in the resulting -/// high-dimensional vector space. Lastly, one can combine these two forms of distance calculation to calculate +/// configurations and then calculate the Euclidean distances between these two points in the resulting +/// high-dimensional vector space. Lastly, one can combine these two forms of distance calculation to calculate /// a hybrid distance. Plumed allows one to use all these forms of distance calculations and also to implement /// new forms of distance. You should inherit from this class if your distance involves reference atomic positions. -/// This class and \ref PLMD::ReferenceArguments mirror the functionalities in and \ref PLMD::ActionAtomistic -/// and \ref PLMD::ActionWithArguments respectively but for distances. +/// This class and \ref PLMD::ReferenceArguments mirror the functionalities in and \ref PLMD::ActionAtomistic +/// and \ref PLMD::ActionWithArguments respectively but for distances. class ReferenceAtoms : virtual public ReferenceConfiguration { -friend class Direction; -friend class SingleDomainRMSD; -friend class ReferenceConfiguration; + friend class Direction; + friend class SingleDomainRMSD; + friend class ReferenceConfiguration; private: /// This flag tells us if the user has disabled checking of the input in order to /// do fancy paths with weird inputs @@ -69,13 +69,13 @@ protected: /// Add atom indices to list void setAtomIndices( const std::vector<AtomNumber>& atomnumbers ); /// Read a list of atoms from the pdb input file - bool parseAtomList( const std::string& , std::vector<unsigned>& ); + bool parseAtomList( const std::string&, std::vector<unsigned>& ); /// Get the vector of alignment weights const std::vector<double> & getAlign() const ; /// Get the vector of displacement weights const std::vector<double> & getDisplace() const ; /// Get the position of the ith atom - Vector getReferencePosition( const unsigned& iatom ) const ; + Vector getReferencePosition( const unsigned& iatom ) const ; /// Add derivatives to iatom th atom in list // void addAtomicDerivatives( const unsigned& , const Vector& ); /// Get the atomic derivatives on the ith atom in the list @@ -105,14 +105,14 @@ public: /// This returns how many atoms there should be unsigned getNumberOfAtoms() const ; /// Displace the positions of the reference atoms a bit - void displaceReferenceAtoms( const double& weight, const std::vector<Vector>& dir ); + void displaceReferenceAtoms( const double& weight, const std::vector<Vector>& dir ); /// Extract a displacement from a position in space virtual void extractAtomicDisplacement( const std::vector<Vector>& pos, const bool & anflag, std::vector<Vector>& direction ) const { - plumed_error(); + plumed_error(); } /// Project the displacement on a vector virtual double projectAtomicDisplacementOnVector( const std::vector<Vector>& eigv, const std::vector<Vector>& pos, ReferenceValuePack& mypack ) const { - plumed_error(); return 1; + plumed_error(); return 1; } }; @@ -171,7 +171,7 @@ const std::vector<Vector> & ReferenceAtoms::getReferencePositions() const { // } inline -const std::vector<AtomNumber>& ReferenceAtoms::getAbsoluteIndexes(){ +const std::vector<AtomNumber>& ReferenceAtoms::getAbsoluteIndexes() { return indices; } diff --git a/src/reference/ReferenceConfiguration.cpp b/src/reference/ReferenceConfiguration.cpp index 1df1bc694..61d554a20 100644 --- a/src/reference/ReferenceConfiguration.cpp +++ b/src/reference/ReferenceConfiguration.cpp @@ -27,10 +27,10 @@ #include "tools/OFile.h" #include "tools/PDB.h" -namespace PLMD{ +namespace PLMD { ReferenceConfigurationOptions::ReferenceConfigurationOptions( const std::string& type ): -tt(type) + tt(type) { } @@ -41,11 +41,11 @@ bool ReferenceConfigurationOptions::usingFastOption() const { std::string ReferenceConfigurationOptions::getMultiRMSDType() const { plumed_assert( tt.find("MULTI-")!=std::string::npos ); std::size_t dot=tt.find_first_of("MULTI-"); - return tt.substr(dot+6); + return tt.substr(dot+6); } ReferenceConfiguration::ReferenceConfiguration( const ReferenceConfigurationOptions& ro ): -name(ro.tt) + name(ro.tt) // arg_ders(0), // atom_ders(0) { @@ -60,11 +60,11 @@ std::string ReferenceConfiguration::getName() const { return name; } -void ReferenceConfiguration::set( const PDB& pdb ){ - line=pdb.getRemark(); - std::string ignore; - if( parse("TYPE",ignore,true) ){ - if(ignore!=name) error("mismatch for name"); +void ReferenceConfiguration::set( const PDB& pdb ) { + line=pdb.getRemark(); + std::string ignore; + if( parse("TYPE",ignore,true) ) { + if(ignore!=name) error("mismatch for name"); } if( !parse("WEIGHT",weight,true) ) weight=1.0; read( pdb ); @@ -83,66 +83,66 @@ void ReferenceConfiguration::set( const PDB& pdb ){ // return virialWasSet; // } -void ReferenceConfiguration::parseFlag( const std::string&key, bool&t ){ +void ReferenceConfiguration::parseFlag( const std::string&key, bool&t ) { Tools::parseFlag(line,key,t); } -void ReferenceConfiguration::error(const std::string& msg){ +void ReferenceConfiguration::error(const std::string& msg) { plumed_merror("error reading reference configuration of type " + name + " : " + msg ); } -void ReferenceConfiguration::setNamesAndAtomNumbers( const std::vector<AtomNumber>& numbers, const std::vector<std::string>& arg ){ - ReferenceAtoms* atoms=dynamic_cast<ReferenceAtoms*>( this ); - if(!atoms){ - plumed_massert( numbers.size()==0, "expecting no atomic positions"); - //setNumberOfAtoms( 0 ); - } else { - atoms->setAtomNumbers( numbers ); - // setNumberOfAtoms( numbers.size() ); +void ReferenceConfiguration::setNamesAndAtomNumbers( const std::vector<AtomNumber>& numbers, const std::vector<std::string>& arg ) { + ReferenceAtoms* atoms=dynamic_cast<ReferenceAtoms*>( this ); + if(!atoms) { + plumed_massert( numbers.size()==0, "expecting no atomic positions"); + //setNumberOfAtoms( 0 ); + } else { + atoms->setAtomNumbers( numbers ); + // setNumberOfAtoms( numbers.size() ); } // Copy the arguments to the reference ReferenceArguments* args=dynamic_cast<ReferenceArguments*>( this ); - if(!args){ - plumed_massert( arg.size()==0, "expecting no arguments"); - // setNumberOfArguments(0); + if(!args) { + plumed_massert( arg.size()==0, "expecting no arguments"); + // setNumberOfArguments(0); } else { - args->setArgumentNames( arg ); - // setNumberOfArguments( arg.size() ); + args->setArgumentNames( arg ); + // setNumberOfArguments( arg.size() ); } } -void ReferenceConfiguration::setReferenceConfig( const std::vector<Vector>& pos, const std::vector<double>& arg, const std::vector<double>& metric ){ +void ReferenceConfiguration::setReferenceConfig( const std::vector<Vector>& pos, const std::vector<double>& arg, const std::vector<double>& metric ) { // plumed_dbg_assert( pos.size()==atom_ders.size() && arg.size()==arg_ders.size() ); // Copy the atomic positions to the reference ReferenceAtoms* atoms=dynamic_cast<ReferenceAtoms*>( this ); - if(!atoms){ - plumed_massert( pos.size()==0, "expecting no atomic positions"); - } else { - std::vector<double> align_in( pos.size(), 1.0 ), displace_in( pos.size(), 1.0 ); - atoms->setReferenceAtoms( pos, align_in, displace_in ); + if(!atoms) { + plumed_massert( pos.size()==0, "expecting no atomic positions"); + } else { + std::vector<double> align_in( pos.size(), 1.0 ), displace_in( pos.size(), 1.0 ); + atoms->setReferenceAtoms( pos, align_in, displace_in ); } // Copy the arguments to the reference ReferenceArguments* args=dynamic_cast<ReferenceArguments*>( this ); - if(!args){ - plumed_massert( arg.size()==0 && metric.size()==0, "expecting no arguments"); + if(!args) { + plumed_massert( arg.size()==0 && metric.size()==0, "expecting no arguments"); } else { - args->setReferenceArguments( arg, metric ); + args->setReferenceArguments( arg, metric ); } } -void ReferenceConfiguration::checkRead(){ - if(!line.empty()){ +void ReferenceConfiguration::checkRead() { + if(!line.empty()) { std::string msg="cannot understand the following words from the input line : "; - for(unsigned i=0;i<line.size();i++) msg = msg + line[i] + ", "; + for(unsigned i=0; i<line.size(); i++) msg = msg + line[i] + ", "; error(msg); } } -double ReferenceConfiguration::calculate( const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& vals, - ReferenceValuePack& myder, const bool& squared ) const { +double ReferenceConfiguration::calculate( const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& vals, + ReferenceValuePack& myder, const bool& squared ) const { // clearDerivatives(); std::vector<double> tmparg( vals.size() ); - for(unsigned i=0;i<vals.size();++i) tmparg[i]=vals[i]->get(); + for(unsigned i=0; i<vals.size(); ++i) tmparg[i]=vals[i]->get(); return calc( pos, pbc, vals, tmparg, myder, squared ); } @@ -153,12 +153,12 @@ double ReferenceConfiguration::calculate( const std::vector<Vector>& pos, const // virialWasSet=ref->virialWasSet; virial=ref->virial; // } -void ReferenceConfiguration::print( OFile& ofile, const double& time, const double& weight, const double& lunits, const double& old_norm ){ +void ReferenceConfiguration::print( OFile& ofile, const double& time, const double& weight, const double& lunits, const double& old_norm ) { ofile.printf("REMARK TIME=%f LOG_WEIGHT=%f OLD_NORM=%f\n",time, weight, old_norm ); print( ofile, "%f", lunits ); // HARD CODED FORMAT HERE AS THIS IS FOR CHECKPOINT FILE } -void ReferenceConfiguration::print( OFile& ofile, const std::string& fmt, const double& lunits ){ +void ReferenceConfiguration::print( OFile& ofile, const std::string& fmt, const double& lunits ) { ofile.printf("REMARK TYPE=%s\n",getName().c_str() ); ReferenceArguments* args=dynamic_cast<ReferenceArguments*>(this); if(args) args->printArguments( ofile, fmt ); @@ -167,61 +167,61 @@ void ReferenceConfiguration::print( OFile& ofile, const std::string& fmt, const ofile.printf("END\n"); } -void ReferenceConfiguration::displaceReferenceConfiguration( const double& weight, Direction& dir ){ +void ReferenceConfiguration::displaceReferenceConfiguration( const double& weight, Direction& dir ) { ReferenceArguments* args=dynamic_cast<ReferenceArguments*>(this); if( args ) args->displaceReferenceArguments( weight, dir.getReferenceArguments() ); ReferenceAtoms* atoms=dynamic_cast<ReferenceAtoms*>(this); if( atoms ) atoms->displaceReferenceAtoms( weight, dir.getReferencePositions() ); } -void ReferenceConfiguration::extractDisplacementVector( const std::vector<Vector>& pos, const std::vector<Value*>& vals, - const std::vector<double>& arg, const bool & anflag, const bool& nflag, - Direction& mydir ) const { +void ReferenceConfiguration::extractDisplacementVector( const std::vector<Vector>& pos, const std::vector<Value*>& vals, + const std::vector<double>& arg, const bool & anflag, const bool& nflag, + Direction& mydir ) const { const ReferenceAtoms* atoms=dynamic_cast<const ReferenceAtoms*>( this ); if( atoms ) atoms->extractAtomicDisplacement( pos, anflag, mydir.reference_atoms ); const ReferenceArguments* args=dynamic_cast<const ReferenceArguments*>( this ); if( args ) args->extractArgumentDisplacement( vals, arg, mydir.reference_args ); // Normalize direction if required - if( nflag ){ - // Calculate length of vector - double tmp, norm=0; - for(unsigned i=0;i<mydir.getReferencePositions().size();++i){ - for(unsigned k=0;k<3;++k){ tmp=mydir.getReferencePositions()[i][k]; norm+=tmp*tmp; } - } - for(unsigned i=0;i<mydir.getReferenceArguments().size();++i){ tmp=mydir.getReferenceArguments()[i]; norm+=tmp*tmp; } - norm = sqrt( norm ); - // And normalize - for(unsigned i=0;i<mydir.getReferencePositions().size();++i){ - for(unsigned k=0;k<3;++k){ mydir.reference_atoms[i][k] /=norm; } - } - for(unsigned i=0;i<mydir.getReferenceArguments().size();++i){ mydir.reference_args[i] /= norm; } + if( nflag ) { + // Calculate length of vector + double tmp, norm=0; + for(unsigned i=0; i<mydir.getReferencePositions().size(); ++i) { + for(unsigned k=0; k<3; ++k) { tmp=mydir.getReferencePositions()[i][k]; norm+=tmp*tmp; } + } + for(unsigned i=0; i<mydir.getReferenceArguments().size(); ++i) { tmp=mydir.getReferenceArguments()[i]; norm+=tmp*tmp; } + norm = sqrt( norm ); + // And normalize + for(unsigned i=0; i<mydir.getReferencePositions().size(); ++i) { + for(unsigned k=0; k<3; ++k) { mydir.reference_atoms[i][k] /=norm; } + } + for(unsigned i=0; i<mydir.getReferenceArguments().size(); ++i) { mydir.reference_args[i] /= norm; } } } double ReferenceConfiguration::projectDisplacementOnVector( const Direction& mydir, const std::vector<Vector>& pos, - const std::vector<Value*>& vals, const std::vector<double>& arg, - ReferenceValuePack& mypack ) const { + const std::vector<Value*>& vals, const std::vector<double>& arg, + ReferenceValuePack& mypack ) const { double proj=0; const ReferenceAtoms* atoms=dynamic_cast<const ReferenceAtoms*>( this ); if( atoms ) proj += atoms->projectAtomicDisplacementOnVector( mydir.getReferencePositions(), pos, mypack ); const ReferenceArguments* args=dynamic_cast<const ReferenceArguments*>( this ); if( args ) proj += args->projectArgDisplacementOnVector( mydir.getReferenceArguments(), vals, arg, mypack ); return proj; -} +} -double distance( const Pbc& pbc, const std::vector<Value*> & vals, ReferenceConfiguration* ref1, ReferenceConfiguration* ref2, const bool& squared ){ +double distance( const Pbc& pbc, const std::vector<Value*> & vals, ReferenceConfiguration* ref1, ReferenceConfiguration* ref2, const bool& squared ) { unsigned nder; if( ref1->getReferencePositions().size()>0 ) nder=ref1->getReferenceArguments().size() + 3*ref1->getReferencePositions().size() + 9; else nder=ref1->getReferenceArguments().size(); - MultiValue myvals( 1, nder ); ReferenceValuePack myder( ref1->getReferenceArguments().size() , ref1->getReferencePositions().size() , myvals ); + MultiValue myvals( 1, nder ); ReferenceValuePack myder( ref1->getReferenceArguments().size(), ref1->getReferencePositions().size(), myvals ); double dist1=ref1->calc( ref2->getReferencePositions(), pbc, vals, ref2->getReferenceArguments(), myder, squared ); #ifndef NDEBUG // Check that A - B = B - A double dist2=ref2->calc( ref1->getReferencePositions(), pbc, vals, ref1->getReferenceArguments(), myder, squared ); plumed_dbg_assert( fabs(dist1-dist2)<epsilon ); -#endif +#endif return dist1; } diff --git a/src/reference/ReferenceConfiguration.h b/src/reference/ReferenceConfiguration.h index e6595dd87..44f39bacc 100644 --- a/src/reference/ReferenceConfiguration.h +++ b/src/reference/ReferenceConfiguration.h @@ -31,7 +31,7 @@ #include "ReferenceValuePack.h" #include "tools/Matrix.h" -namespace PLMD{ +namespace PLMD { class Value; class Pbc; @@ -40,7 +40,7 @@ class PDB; class Direction; class ReferenceConfigurationOptions { -friend class ReferenceConfiguration; + friend class ReferenceConfiguration; private: std::string tt; public: @@ -52,16 +52,16 @@ public: /// \ingroup INHERIT /// Abstract base class for calculating the distance from a reference configuration. /// A reference configuration can either have a particular set of atoms in a particular -/// given configuration or it can be that a particular set of colvars have a particular +/// given configuration or it can be that a particular set of colvars have a particular /// set of values. It could also be a combination of both. To allow all the posible -/// permutations and in order make it easy to add new ways of calculating the distance -/// we have implemented this using polymorphism and multiple inheritance. The following -/// provides \ref AddingAMetric "information" on how to implement a new method for +/// permutations and in order make it easy to add new ways of calculating the distance +/// we have implemented this using polymorphism and multiple inheritance. The following +/// provides \ref AddingAMetric "information" on how to implement a new method for /// calculating the distance between a pair of configurations class ReferenceConfiguration { -friend class SingleDomainRMSD; -friend double distance( const Pbc& pbc, const std::vector<Value*> & vals, ReferenceConfiguration*, ReferenceConfiguration*, const bool& squared ); + friend class SingleDomainRMSD; + friend double distance( const Pbc& pbc, const std::vector<Value*> & vals, ReferenceConfiguration*, ReferenceConfiguration*, const bool& squared ); private: /// The name of this particular config std::string name; @@ -81,14 +81,14 @@ private: protected: /// Derivatives wrt to the arguments // std::vector<double> arg_ders; -/// The virial contribution has to be stored +/// The virial contribution has to be stored // bool virialWasSet; // Tensor virial; /// Derivatives wrt to the atoms // std::vector<Vector> atom_ders; /// Crash with an error void error(const std::string& msg); -/// Clear the derivatives +/// Clear the derivatives // void clearDerivatives(); public: explicit ReferenceConfiguration( const ReferenceConfigurationOptions& ro ); @@ -100,16 +100,16 @@ public: virtual unsigned getNumberOfReferencePositions() const ; virtual unsigned getNumberOfReferenceArguments() const ; /// Retrieve the atoms that are required for this guy - virtual void getAtomRequests( std::vector<AtomNumber>&, bool disable_checks=false ){} + virtual void getAtomRequests( std::vector<AtomNumber>&, bool disable_checks=false ) {} /// Retrieve the arguments that are required for this guy - virtual void getArgumentRequests( std::vector<std::string>&, bool disable_checks=false ){} + virtual void getArgumentRequests( std::vector<std::string>&, bool disable_checks=false ) {} /// Set the final number of arguments // virtual void setNumberOfArguments( const unsigned& ); /// Set the final number of atoms // virtual void setNumberOfAtoms( const unsigned& ); -/// Set the reference configuration using a PDB +/// Set the reference configuration using a PDB virtual void set( const PDB& ); -/// Do all local business for setting the configuration +/// Do all local business for setting the configuration virtual void read( const PDB& )=0; /// Set the weight for this frame void setWeight( const double& ww ); @@ -118,16 +118,16 @@ public: /// Calculate the distance from the reference configuration double calculate( const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& vals, ReferenceValuePack& myder, const bool& squared=false ) const ; /// Calculate the distance from the reference configuration - virtual double calc( const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& vals, const std::vector<double>& args, + virtual double calc( const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& vals, const std::vector<double>& args, ReferenceValuePack& myder, const bool& squared ) const=0; // /// Return the derivative wrt to the ith atom // Vector getAtomDerivative( const unsigned& ) const ; // /// Return the derivative wrt to the ith argument // double getArgumentDerivative( const unsigned& ) const ; /// Return the derivatives of the distance wrt the cell vectors. This returns false -/// for everything other than DRMSD as these sort of calculations have to be done -/// separately when you use RMSD -// bool getVirial( Tensor& virout ) const ; +/// for everything other than DRMSD as these sort of calculations have to be done +/// separately when you use RMSD +// bool getVirial( Tensor& virout ) const ; /// Parse something from the pdb remarks template<class T> bool parse( const std::string&key, T&t, bool ignore_missing=false ); @@ -149,24 +149,24 @@ public: void print( OFile& ofile, const std::string& fmt, const double& lunits ); /// Get one of the referene arguments virtual double getReferenceArgument( const unsigned& i ) const { plumed_error(); return 0.0; } -/// These are overwritten in ReferenceArguments and ReferenceAtoms but are required here +/// These are overwritten in ReferenceArguments and ReferenceAtoms but are required here /// to make PLMD::distance work - virtual const std::vector<Vector>& getReferencePositions() const ; - virtual const std::vector<double>& getReferenceArguments() const ; + virtual const std::vector<Vector>& getReferencePositions() const ; + virtual const std::vector<double>& getReferenceArguments() const ; virtual const std::vector<double>& getReferenceMetric(); /// These are overwritten in ReferenceArguments and ReferenceAtoms to make frame copying work virtual const std::vector<AtomNumber>& getAbsoluteIndexes(); virtual const std::vector<std::string>& getArgumentNames(); /// Extract a Direction giving you the displacement from some position void extractDisplacementVector( const std::vector<Vector>& pos, const std::vector<Value*>& vals, - const std::vector<double>& arg, const bool& anflag, const bool& nflag, + const std::vector<double>& arg, const bool& anflag, const bool& nflag, Direction& mydir ) const ; /// Stuff for pca - virtual bool pcaIsEnabledForThisReference(){ return false; } - double projectDisplacementOnVector( const Direction& mydir, const std::vector<Vector>& pos, const std::vector<Value*>& vals, + virtual bool pcaIsEnabledForThisReference() { return false; } + double projectDisplacementOnVector( const Direction& mydir, const std::vector<Vector>& pos, const std::vector<Value*>& vals, const std::vector<double>& arg, ReferenceValuePack& mypack ) const ; /// Stuff to setup pca - virtual void setupPCAStorage( ReferenceValuePack& mypack ){ plumed_error(); } + virtual void setupPCAStorage( ReferenceValuePack& mypack ) { plumed_error(); } /// Move the reference configuration by an ammount specified using a Direction void displaceReferenceConfiguration( const double& weight, Direction& dir ); }; @@ -184,7 +184,7 @@ public: // } inline -void ReferenceConfiguration::setWeight( const double& ww ){ +void ReferenceConfiguration::setWeight( const double& ww ) { weight=ww; } @@ -194,21 +194,21 @@ double ReferenceConfiguration::getWeight() const { } template<class T> -bool ReferenceConfiguration::parse(const std::string&key, T&t, bool ignore_missing ){ +bool ReferenceConfiguration::parse(const std::string&key, T&t, bool ignore_missing ) { bool found=Tools::parse(line,key,t); - if(!ignore_missing && !found) error(key + " is missing"); + if(!ignore_missing && !found) error(key + " is missing"); return found; } template<class T> -bool ReferenceConfiguration::parseVector(const std::string&key,std::vector<T>&t, bool ignore_missing){ +bool ReferenceConfiguration::parseVector(const std::string&key,std::vector<T>&t, bool ignore_missing) { bool found=Tools::parseVector(line,key,t); if(!ignore_missing && !found) error(key + " is missing"); return found; } inline -const std::vector<Vector>& ReferenceConfiguration::getReferencePositions() const { +const std::vector<Vector>& ReferenceConfiguration::getReferencePositions() const { return fake_refatoms; } @@ -218,17 +218,17 @@ const std::vector<double>& ReferenceConfiguration::getReferenceArguments() const } inline -const std::vector<double>& ReferenceConfiguration::getReferenceMetric(){ +const std::vector<double>& ReferenceConfiguration::getReferenceMetric() { return fake_metric; } inline -const std::vector<AtomNumber>& ReferenceConfiguration::getAbsoluteIndexes(){ +const std::vector<AtomNumber>& ReferenceConfiguration::getAbsoluteIndexes() { return fake_atom_numbers; } inline -const std::vector<std::string>& ReferenceConfiguration::getArgumentNames(){ +const std::vector<std::string>& ReferenceConfiguration::getArgumentNames() { return fake_arg_names; } diff --git a/src/reference/ReferenceValuePack.cpp b/src/reference/ReferenceValuePack.cpp index 9fd9fc6f8..106e1f148 100644 --- a/src/reference/ReferenceValuePack.cpp +++ b/src/reference/ReferenceValuePack.cpp @@ -24,72 +24,72 @@ namespace PLMD { ReferenceValuePack::ReferenceValuePack( const unsigned& nargs, const unsigned& natoms, MultiValue& vals ): -boxWasSet(false), -numberOfArgs(nargs), -oind_set(false), -myvals(vals), -atom_indices(myvals.getIndices()), -pca(false) + boxWasSet(false), + numberOfArgs(nargs), + oind_set(false), + myvals(vals), + atom_indices(myvals.getIndices()), + pca(false) { - if( atom_indices.size()!=natoms ){ atom_indices.resize( natoms ); myvals.getAtomVector().resize( natoms ); } - if( vals.getNumberOfValues()==1 ){ oind=0; oind_set=true; } + if( atom_indices.size()!=natoms ) { atom_indices.resize( natoms ); myvals.getAtomVector().resize( natoms ); } + if( vals.getNumberOfValues()==1 ) { oind=0; oind_set=true; } } -void ReferenceValuePack::resize( const unsigned& nargs, const unsigned& natoms ){ - numberOfArgs=nargs; atom_indices.resize( natoms ); +void ReferenceValuePack::resize( const unsigned& nargs, const unsigned& natoms ) { + numberOfArgs=nargs; atom_indices.resize( natoms ); myvals.getAtomVector().resize( natoms ); } -void ReferenceValuePack::updateDynamicLists(){ +void ReferenceValuePack::updateDynamicLists() { myvals.emptyActiveMembers(); - for(unsigned i=0;i<numberOfArgs;++i) myvals.putIndexInActiveArray( i ); - for(unsigned i=0;i<atom_indices.size();++i){ - unsigned nbase = numberOfArgs + 3*atom_indices[i]; - if( atom_indices[i]<myvals.getNumberOfDerivatives() && myvals.isActive( nbase ) ){ - myvals.putIndexInActiveArray( nbase+0 ); myvals.putIndexInActiveArray( nbase+1 ); myvals.putIndexInActiveArray( nbase+2 ); - } + for(unsigned i=0; i<numberOfArgs; ++i) myvals.putIndexInActiveArray( i ); + for(unsigned i=0; i<atom_indices.size(); ++i) { + unsigned nbase = numberOfArgs + 3*atom_indices[i]; + if( atom_indices[i]<myvals.getNumberOfDerivatives() && myvals.isActive( nbase ) ) { + myvals.putIndexInActiveArray( nbase+0 ); myvals.putIndexInActiveArray( nbase+1 ); myvals.putIndexInActiveArray( nbase+2 ); + } } unsigned nbase = myvals.getNumberOfDerivatives() - 9; // zero is added to all virial components to ensure that these are active in the dynamic list // if this is not done there is a problem with secondary structure variables - if( atom_indices.size()>0 ){ - for(unsigned i=0;i<9;++i){ - myvals.addDerivative( oind, nbase+i, 0.0 ); - myvals.putIndexInActiveArray( nbase+i ); - } - } + if( atom_indices.size()>0 ) { + for(unsigned i=0; i<9; ++i) { + myvals.addDerivative( oind, nbase+i, 0.0 ); + myvals.putIndexInActiveArray( nbase+i ); + } + } myvals.completeUpdate(); } -void ReferenceValuePack::clear(){ +void ReferenceValuePack::clear() { if( !myvals.updateComplete() ) updateDynamicLists(); myvals.clearAll(); boxWasSet=false; } -void ReferenceValuePack::scaleAllDerivatives( const double& scalef ){ +void ReferenceValuePack::scaleAllDerivatives( const double& scalef ) { if( !myvals.updateComplete() ) updateDynamicLists(); - for(unsigned i=0;i<myvals.getNumberActive();++i){ - unsigned ider=myvals.getActiveIndex(i); - myvals.setDerivative( oind, ider, scalef*myvals.getDerivative( oind, ider ) ); + for(unsigned i=0; i<myvals.getNumberActive(); ++i) { + unsigned ider=myvals.getActiveIndex(i); + myvals.setDerivative( oind, ider, scalef*myvals.getDerivative( oind, ider ) ); } } -void ReferenceValuePack::copyScaledDerivatives( const unsigned& from, const double& scalef, const MultiValue& tvals ){ +void ReferenceValuePack::copyScaledDerivatives( const unsigned& from, const double& scalef, const MultiValue& tvals ) { plumed_dbg_assert( tvals.getNumberOfDerivatives()==myvals.getNumberOfDerivatives() ); - for(unsigned i=0;i<tvals.getNumberActive();++i){ - unsigned ider=tvals.getActiveIndex(i); - myvals.addDerivative( oind, ider, scalef*tvals.getDerivative( from, ider ) ); + for(unsigned i=0; i<tvals.getNumberActive(); ++i) { + unsigned ider=tvals.getActiveIndex(i); + myvals.addDerivative( oind, ider, scalef*tvals.getDerivative( from, ider ) ); } } -void ReferenceValuePack::moveDerivatives( const unsigned& from, const unsigned& to ){ +void ReferenceValuePack::moveDerivatives( const unsigned& from, const unsigned& to ) { if( !myvals.updateComplete() ) updateDynamicLists(); - for(unsigned i=0;i<myvals.getNumberActive();++i){ - unsigned ider=myvals.getActiveIndex(i); - myvals.setDerivative( to, ider, myvals.getDerivative( from, ider ) ); - } + for(unsigned i=0; i<myvals.getNumberActive(); ++i) { + unsigned ider=myvals.getActiveIndex(i); + myvals.setDerivative( to, ider, myvals.getDerivative( from, ider ) ); + } } } diff --git a/src/reference/ReferenceValuePack.h b/src/reference/ReferenceValuePack.h index db352e68e..d5bc2078b 100644 --- a/src/reference/ReferenceValuePack.h +++ b/src/reference/ReferenceValuePack.h @@ -27,8 +27,8 @@ namespace PLMD { class ReferenceValuePack { -friend class MultiDomainRMSD; -friend class OptimalRMSD; + friend class MultiDomainRMSD; + friend class OptimalRMSD; private: /// Was the virial set bool boxWasSet; @@ -41,7 +41,7 @@ private: MultiValue& myvals; /// Ths list of atom indices std::vector<unsigned>& atom_indices; -/// Are we using pca +/// Are we using pca bool pca; /// A vector of vectors to save us some overhead for vector resizes std::vector<Vector> centeredpos; @@ -79,7 +79,7 @@ public: void addAtomDerivatives( const unsigned& iatom, const Vector& der ); /// void addBoxDerivatives( const Tensor& vir ); -/// +/// bool updateComplete() const ; /// void updateDynamicLists(); @@ -123,23 +123,23 @@ unsigned ReferenceValuePack::getNumberOfAtoms() const { } inline -void ReferenceValuePack::setAtomIndex( const unsigned& iatom, const unsigned& jindex ){ +void ReferenceValuePack::setAtomIndex( const unsigned& iatom, const unsigned& jindex ) { plumed_dbg_assert( iatom<atom_indices.size() ); atom_indices[iatom]=jindex; } inline unsigned ReferenceValuePack::getAtomIndex( const unsigned& iatom ) const { - plumed_dbg_assert( iatom<atom_indices.size() ); + plumed_dbg_assert( iatom<atom_indices.size() ); return atom_indices[iatom]; } inline -void ReferenceValuePack::addArgumentDerivatives( const unsigned& iarg, const double& der ){ +void ReferenceValuePack::addArgumentDerivatives( const unsigned& iarg, const double& der ) { plumed_dbg_assert( iarg<numberOfArgs && oind_set ); myvals.addDerivative( oind, iarg, der ); } inline -void ReferenceValuePack::setArgumentDerivatives( const unsigned& iarg, const double& der ){ +void ReferenceValuePack::setArgumentDerivatives( const unsigned& iarg, const double& der ) { plumed_dbg_assert( iarg<numberOfArgs && oind_set ); myvals.setDerivative( oind, iarg, der ); } @@ -149,7 +149,7 @@ bool ReferenceValuePack::updateComplete() const { } inline -void ReferenceValuePack::setAtomDerivatives( const unsigned& jder, const Vector& der ){ +void ReferenceValuePack::setAtomDerivatives( const unsigned& jder, const Vector& der ) { plumed_dbg_assert( oind_set && jder<atom_indices.size() ); myvals.setDerivative( oind, numberOfArgs + 3*atom_indices[jder] + 0, der[0] ); myvals.setDerivative( oind, numberOfArgs + 3*atom_indices[jder] + 1, der[1] ); @@ -157,7 +157,7 @@ void ReferenceValuePack::setAtomDerivatives( const unsigned& jder, const Vector& } inline -void ReferenceValuePack::addAtomDerivatives( const unsigned& jder, const Vector& der ){ +void ReferenceValuePack::addAtomDerivatives( const unsigned& jder, const Vector& der ) { plumed_dbg_assert( oind_set && jder<atom_indices.size() ); myvals.addDerivative( oind, numberOfArgs + 3*atom_indices[jder] + 0, der[0] ); myvals.addDerivative( oind, numberOfArgs + 3*atom_indices[jder] + 1, der[1] ); @@ -165,14 +165,14 @@ void ReferenceValuePack::addAtomDerivatives( const unsigned& jder, const Vector& } inline -void ReferenceValuePack::addBoxDerivatives( const Tensor& vir ){ +void ReferenceValuePack::addBoxDerivatives( const Tensor& vir ) { plumed_dbg_assert( oind_set && atom_indices.size()>0 ); boxWasSet=true; unsigned nbase = myvals.getNumberOfDerivatives() - 9; - for(unsigned i=0;i<3;++i) for(unsigned j=0;j<3;++j) myvals.addDerivative( oind, nbase + 3*i + j , vir(i,j) ); + for(unsigned i=0; i<3; ++i) for(unsigned j=0; j<3; ++j) myvals.addDerivative( oind, nbase + 3*i + j, vir(i,j) ); } inline -void ReferenceValuePack::setValIndex( const unsigned& ind ){ +void ReferenceValuePack::setValIndex( const unsigned& ind ) { oind=ind; oind_set=true; } @@ -186,7 +186,7 @@ Vector ReferenceValuePack::getAtomDerivative( const unsigned& iatom ) const { Vector tmp; plumed_dbg_assert( oind_set && iatom<atom_indices.size() ); tmp[0]=myvals.getDerivative( oind, numberOfArgs + 3*atom_indices[iatom] + 0 ); tmp[1]=myvals.getDerivative( oind, numberOfArgs + 3*atom_indices[iatom] + 1 ); - tmp[2]=myvals.getDerivative( oind, numberOfArgs + 3*atom_indices[iatom] + 2 ); + tmp[2]=myvals.getDerivative( oind, numberOfArgs + 3*atom_indices[iatom] + 2 ); return tmp; } @@ -199,7 +199,7 @@ double ReferenceValuePack::getArgumentDerivative( const unsigned& ival ) const { inline Tensor ReferenceValuePack::getBoxDerivatives() const { plumed_dbg_assert( oind_set && boxWasSet ); Tensor tvir; unsigned nbase = myvals.getNumberOfDerivatives() - 9; - for(unsigned i=0;i<3;++i) for(unsigned j=0;j<3;++j) tvir(i,j)=myvals.getDerivative( oind, nbase + 3*i + j ); + for(unsigned i=0; i<3; ++i) for(unsigned j=0; j<3; ++j) tvir(i,j)=myvals.getDerivative( oind, nbase + 3*i + j ); return tvir; } @@ -209,17 +209,17 @@ bool ReferenceValuePack::calcUsingPCAOption() const { } inline -void ReferenceValuePack::switchOnPCAOption(){ +void ReferenceValuePack::switchOnPCAOption() { pca=true; } inline -std::vector<Vector>& ReferenceValuePack::getAtomVector(){ +std::vector<Vector>& ReferenceValuePack::getAtomVector() { return myvals.getAtomVector(); } inline -std::vector<Vector>& ReferenceValuePack::getAtomsDisplacementVector(){ +std::vector<Vector>& ReferenceValuePack::getAtomsDisplacementVector() { return displacement; } diff --git a/src/reference/SimpleRMSD.cpp b/src/reference/SimpleRMSD.cpp index 9b06563ed..4c0d82532 100644 --- a/src/reference/SimpleRMSD.cpp +++ b/src/reference/SimpleRMSD.cpp @@ -23,7 +23,7 @@ #include "MetricRegister.h" #include "tools/RMSD.h" -namespace PLMD{ +namespace PLMD { class SimpleRMSD : public RMSDBase { private: @@ -32,30 +32,30 @@ public: explicit SimpleRMSD( const ReferenceConfigurationOptions& ro ); void read( const PDB& ); double calc( const std::vector<Vector>& pos, ReferenceValuePack& myder, const bool& squared ) const ; - bool pcaIsEnabledForThisReference(){ return true; } - void setupPCAStorage( ReferenceValuePack& mypack ){ - mypack.switchOnPCAOption(); mypack.getAtomsDisplacementVector().resize( getNumberOfAtoms() ); + bool pcaIsEnabledForThisReference() { return true; } + void setupPCAStorage( ReferenceValuePack& mypack ) { + mypack.switchOnPCAOption(); mypack.getAtomsDisplacementVector().resize( getNumberOfAtoms() ); } void extractAtomicDisplacement( const std::vector<Vector>& pos, const bool& anflag, std::vector<Vector>& direction ) const ; - double projectAtomicDisplacementOnVector( const std::vector<Vector>& vecs, const std::vector<Vector>& pos, ReferenceValuePack& mypack ) const ; + double projectAtomicDisplacementOnVector( const std::vector<Vector>& vecs, const std::vector<Vector>& pos, ReferenceValuePack& mypack ) const ; }; PLUMED_REGISTER_METRIC(SimpleRMSD,"SIMPLE") SimpleRMSD::SimpleRMSD( const ReferenceConfigurationOptions& ro ): -ReferenceConfiguration( ro ), -RMSDBase( ro ) + ReferenceConfiguration( ro ), + RMSDBase( ro ) { } -void SimpleRMSD::read( const PDB& pdb ){ +void SimpleRMSD::read( const PDB& pdb ) { readReference( pdb ); } double SimpleRMSD::calc( const std::vector<Vector>& pos, ReferenceValuePack& myder, const bool& squared ) const { if( myder.getAtomsDisplacementVector().size()!=pos.size() ) myder.getAtomsDisplacementVector().resize( pos.size() ); double d=myrmsd.simpleAlignment( getAlign(), getDisplace(), pos, getReferencePositions(), myder.getAtomVector(), myder.getAtomsDisplacementVector(), squared ); - myder.clear(); for(unsigned i=0;i<pos.size();++i) myder.setAtomDerivatives( i, myder.getAtomVector()[i] ); + myder.clear(); for(unsigned i=0; i<pos.size(); ++i) myder.setAtomDerivatives( i, myder.getAtomVector()[i] ); if( !myder.updateComplete() ) myder.updateDynamicLists(); return d; } @@ -64,21 +64,21 @@ void SimpleRMSD::extractAtomicDisplacement( const std::vector<Vector>& pos, cons std::vector<Vector> tder( getNumberOfAtoms() ); double d=myrmsd.simpleAlignment( getAlign(), getDisplace(), pos, getReferencePositions(), tder, direction, true ); double scale=1.0; if( anflag ) scale = 1.0 / static_cast<double>( pos.size() ); - for(unsigned i=0;i<pos.size();++i) direction[i] = scale*direction[i]; + for(unsigned i=0; i<pos.size(); ++i) direction[i] = scale*direction[i]; } -double SimpleRMSD::projectAtomicDisplacementOnVector( const std::vector<Vector>& vecs, const std::vector<Vector>& pos, ReferenceValuePack& mypack ) const { +double SimpleRMSD::projectAtomicDisplacementOnVector( const std::vector<Vector>& vecs, const std::vector<Vector>& pos, ReferenceValuePack& mypack ) const { plumed_dbg_assert( mypack.calcUsingPCAOption() ); Vector comder; comder.zero(); - for(unsigned j=0;j<pos.size();++j){ - for(unsigned k=0;k<3;++k) comder[k] += getAlign()[j]*vecs[j][k]; + for(unsigned j=0; j<pos.size(); ++j) { + for(unsigned k=0; k<3; ++k) comder[k] += getAlign()[j]*vecs[j][k]; } double proj=0; mypack.clear(); - for(unsigned j=0;j<pos.size();++j){ - for(unsigned k=0;k<3;++k){ - proj += vecs[j][k]*mypack.getAtomsDisplacementVector()[j][k]; - } - mypack.setAtomDerivatives( j, vecs[j] - comder ); + for(unsigned j=0; j<pos.size(); ++j) { + for(unsigned k=0; k<3; ++k) { + proj += vecs[j][k]*mypack.getAtomsDisplacementVector()[j][k]; + } + mypack.setAtomDerivatives( j, vecs[j] - comder ); } if( !mypack.updateComplete() ) mypack.updateDynamicLists(); return proj; diff --git a/src/reference/SingleDomainRMSD.cpp b/src/reference/SingleDomainRMSD.cpp index 2a692cf85..a499e6670 100644 --- a/src/reference/SingleDomainRMSD.cpp +++ b/src/reference/SingleDomainRMSD.cpp @@ -26,36 +26,36 @@ namespace PLMD { SingleDomainRMSD::SingleDomainRMSD( const ReferenceConfigurationOptions& ro ): -ReferenceConfiguration(ro), -ReferenceAtoms(ro) + ReferenceConfiguration(ro), + ReferenceAtoms(ro) { } -void SingleDomainRMSD::readReference( const PDB& pdb ){ +void SingleDomainRMSD::readReference( const PDB& pdb ) { readAtomsFromPDB( pdb ); double wa=0, wd=0; - for(unsigned i=0;i<pdb.size();++i){ wa+=align[i]; wd+=displace[i]; } + for(unsigned i=0; i<pdb.size(); ++i) { wa+=align[i]; wd+=displace[i]; } Vector center; - for(unsigned i=0;i<pdb.size();++i){ - align[i]=align[i] / wa; displace[i]=displace[i] / wd; - center+=reference_atoms[i]*align[i]; + for(unsigned i=0; i<pdb.size(); ++i) { + align[i]=align[i] / wa; displace[i]=displace[i] / wd; + center+=reference_atoms[i]*align[i]; } - for(unsigned i=0;i<pdb.size();++i) reference_atoms[i]-=center; -} + for(unsigned i=0; i<pdb.size(); ++i) reference_atoms[i]-=center; +} -void SingleDomainRMSD::setReferenceAtoms( const std::vector<Vector>& conf, const std::vector<double>& align_in, const std::vector<double>& displace_in ){ - reference_atoms.resize( conf.size() ); align.resize( conf.size() ); +void SingleDomainRMSD::setReferenceAtoms( const std::vector<Vector>& conf, const std::vector<double>& align_in, const std::vector<double>& displace_in ) { + reference_atoms.resize( conf.size() ); align.resize( conf.size() ); displace.resize( conf.size() ); atom_der_index.resize( conf.size() ); - double wa=0, wd=0; - for(unsigned i=0;i<conf.size();++i){ wa+=align_in[i]; wd+=displace_in[i]; } - - Vector center; - for(unsigned i=0;i<conf.size();++i){ - align[i]=align_in[i] / wa; displace[i]=displace_in[i] / wd; - center+=conf[i]*align[i]; atom_der_index[i]=i; + double wa=0, wd=0; + for(unsigned i=0; i<conf.size(); ++i) { wa+=align_in[i]; wd+=displace_in[i]; } + + Vector center; + for(unsigned i=0; i<conf.size(); ++i) { + align[i]=align_in[i] / wa; displace[i]=displace_in[i] / wd; + center+=conf[i]*align[i]; atom_der_index[i]=i; } - for(unsigned i=0;i<conf.size();++i) reference_atoms[i]=conf[i]-center; + for(unsigned i=0; i<conf.size(); ++i) reference_atoms[i]=conf[i]-center; setupRMSDObject(); } @@ -63,7 +63,7 @@ double SingleDomainRMSD::calculate( const std::vector<Vector>& pos, const Pbc& p return calc( pos, pbc, myder, squared ); } -double SingleDomainRMSD::calc( const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& vals, const std::vector<double>& arg, +double SingleDomainRMSD::calc( const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& vals, const std::vector<double>& arg, ReferenceValuePack& myder, const bool& squared ) const { plumed_dbg_assert( vals.size()==0 && pos.size()==getNumberOfAtoms() && arg.size()==0 ); return calc( pos, pbc, myder, squared ); diff --git a/src/reference/SingleDomainRMSD.h b/src/reference/SingleDomainRMSD.h index 9c6369e55..9ecf96123 100644 --- a/src/reference/SingleDomainRMSD.h +++ b/src/reference/SingleDomainRMSD.h @@ -36,14 +36,14 @@ public: /// Set the reference structure virtual void setReferenceAtoms( const std::vector<Vector>& conf, const std::vector<double>& align_in, const std::vector<double>& displace_in ); /// Calculate - double calc( const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& vals, const std::vector<double>& arg, ReferenceValuePack& myder, const bool& squared ) const; + double calc( const std::vector<Vector>& pos, const Pbc& pbc, const std::vector<Value*>& vals, const std::vector<double>& arg, ReferenceValuePack& myder, const bool& squared ) const; double calculate( const std::vector<Vector>& pos, const Pbc& pbc, ReferenceValuePack& myder, const bool& squared ) const; /// Calculate the distance using the input position virtual double calc( const std::vector<Vector>& pos, const Pbc& pbc, ReferenceValuePack& myder, const bool& squared ) const=0; /// This sets upper and lower bounds on distances to be used in DRMSD (here it does nothing) - virtual void setBoundsOnDistances( bool dopbc, double lbound=0.0, double ubound=std::numeric_limits<double>::max( ) ){}; + virtual void setBoundsOnDistances( bool dopbc, double lbound=0.0, double ubound=std::numeric_limits<double>::max( ) ) {}; /// This is used by MultiDomainRMSD to setup the RMSD object in Optimal RMSD type - virtual void setupRMSDObject(){}; + virtual void setupRMSDObject() {}; }; } diff --git a/src/secondarystructure/AlphaRMSD.cpp b/src/secondarystructure/AlphaRMSD.cpp index 0f29dc024..6c9b49083 100644 --- a/src/secondarystructure/AlphaRMSD.cpp +++ b/src/secondarystructure/AlphaRMSD.cpp @@ -34,13 +34,13 @@ Probe the alpha helical content of a protein structure. Any chain of six contiguous residues in a protein chain can form an alpha helix. This colvar thus generates the set of all possible six residue sections and calculates the RMSD distance between the configuration in which the residues find themselves -and an idealized alpha helical structure. These distances can be calculated by either +and an idealized alpha helical structure. These distances can be calculated by either aligning the instantaneous structure with the reference structure and measuring each atomic displacement or by calculating differences between the set of interatomic -distances in the reference and instantaneous structures. +distances in the reference and instantaneous structures. -This colvar is based on the following reference \cite pietrucci09jctc. The authors of -this paper use the set of distances from the alpha helix configurations to measure +This colvar is based on the following reference \cite pietrucci09jctc. The authors of +this paper use the set of distances from the alpha helix configurations to measure the number of segments that have an alpha helical configuration. This is done by calculating the following sum of functions of the rmsd distances: @@ -48,24 +48,24 @@ the following sum of functions of the rmsd distances: s = \sum_i \frac{ 1 - \left(\frac{r_i-d_0}{r_0}\right)^n } { 1 - \left(\frac{r_i-d_0}{r_0}\right)^m } \f] -where the sum runs over all possible segments of alpha helix. By default the +where the sum runs over all possible segments of alpha helix. By default the NN, MM and D_0 parameters are set equal to those used in \cite pietrucci09jctc. The R_0 parameter must be set by the user - the value used in \cite pietrucci09jctc was 0.08 nm. If you change the function in the above sum you can calculate quantities such as the average -distance from a purely the alpha helical configuration or the distance between the set of -residues that is closest to an alpha helix and the reference configuration. To do these sorts of +distance from a purely the alpha helical configuration or the distance between the set of +residues that is closest to an alpha helix and the reference configuration. To do these sorts of calculations you can use the AVERAGE and MIN keywords. In addition you can use the LESS_THAN keyword if you would like to change the form of the switching function. If you use any of these -options you no longer need to specify NN, R_0, MM and D_0. +options you no longer need to specify NN, R_0, MM and D_0. -Please be aware that for codes like gromacs you must ensure that plumed +Please be aware that for codes like gromacs you must ensure that plumed reconstructs the chains involved in your CV when you calculate this CV using anthing other than TYPE=DRMSD. For more details as to how to do this see \ref WHOLEMOLECULES. \par Examples -The following input calculates the number of six residue segments of +The following input calculates the number of six residue segments of protein that are in an alpha helical configuration. \verbatim @@ -81,33 +81,33 @@ class AlphaRMSD : public SecondaryStructureRMSD { public: static void registerKeywords( Keywords& keys ); explicit AlphaRMSD(const ActionOptions&); -}; +}; PLUMED_REGISTER_ACTION(AlphaRMSD,"ALPHARMSD") -void AlphaRMSD::registerKeywords( Keywords& keys ){ +void AlphaRMSD::registerKeywords( Keywords& keys ) { SecondaryStructureRMSD::registerKeywords( keys ); } AlphaRMSD::AlphaRMSD(const ActionOptions&ao): -Action(ao), -SecondaryStructureRMSD(ao) + Action(ao), + SecondaryStructureRMSD(ao) { // read in the backbone atoms std::vector<unsigned> chains; readBackboneAtoms( "protein", chains); // This constructs all conceivable sections of alpha helix in the backbone of the chains unsigned nres, nprevious=0; std::vector<unsigned> nlist(30); - for(unsigned i=0;i<chains.size();++i){ - if( chains[i]<30 ) error("segment of backbone defined is not long enough to form an alpha helix. Each backbone fragment must contain a minimum of 6 residues"); - nres=chains[i]/5; - if( chains[i]%5!=0 ) error("backbone segment received does not contain a multiple of five residues"); - for(unsigned ires=0;ires<nres-5;ires++){ - unsigned accum=nprevious + 5*ires; - for(unsigned k=0;k<30;++k) nlist[k] = accum+k; - addColvar( nlist ); - } - nprevious+=chains[i]; + for(unsigned i=0; i<chains.size(); ++i) { + if( chains[i]<30 ) error("segment of backbone defined is not long enough to form an alpha helix. Each backbone fragment must contain a minimum of 6 residues"); + nres=chains[i]/5; + if( chains[i]%5!=0 ) error("backbone segment received does not contain a multiple of five residues"); + for(unsigned ires=0; ires<nres-5; ires++) { + unsigned accum=nprevious + 5*ires; + for(unsigned k=0; k<30; ++k) nlist[k] = accum+k; + addColvar( nlist ); + } + nprevious+=chains[i]; } // Build the reference structure ( in angstroms ) @@ -143,7 +143,7 @@ SecondaryStructureRMSD(ao) reference[28] = Vector(-1.663, -0.171, -4.475 ); // C reference[29] = Vector(-1.916, -0.296, -5.673 ); // O // Store the secondary structure ( last number makes sure we convert to internal units nm ) - setSecondaryStructure( reference, 0.17/atoms.getUnits().getLength(), 0.1/atoms.getUnits().getLength() ); + setSecondaryStructure( reference, 0.17/atoms.getUnits().getLength(), 0.1/atoms.getUnits().getLength() ); } } diff --git a/src/secondarystructure/AntibetaRMSD.cpp b/src/secondarystructure/AntibetaRMSD.cpp index 4a1fa335a..6e60d5445 100644 --- a/src/secondarystructure/AntibetaRMSD.cpp +++ b/src/secondarystructure/AntibetaRMSD.cpp @@ -31,18 +31,18 @@ namespace secondarystructure { /* Probe the antiparallel beta sheet content of your protein structure. -Two protein segments containing three continguous residues can form an antiparallel beta sheet. -Although if the two segments are part of the same protein chain they must be separated by -a minimum of 2 residues to make room for the turn. This colvar thus generates the set of -all possible six residue sections that could conceivably form an antiparallel beta sheet +Two protein segments containing three continguous residues can form an antiparallel beta sheet. +Although if the two segments are part of the same protein chain they must be separated by +a minimum of 2 residues to make room for the turn. This colvar thus generates the set of +all possible six residue sections that could conceivably form an antiparallel beta sheet and calculates the RMSD distance between the configuration in which the residues find themselves -and an idealized antiparallel beta sheet structure. These distances can be calculated by either +and an idealized antiparallel beta sheet structure. These distances can be calculated by either aligning the instantaneous structure with the reference structure and measuring each atomic displacement or by calculating differences between the set of interatomic -distances in the reference and instantaneous structures. +distances in the reference and instantaneous structures. -This colvar is based on the following reference \cite pietrucci09jctc. The authors of -this paper use the set of distances from the anti parallel beta sheet configurations to measure +This colvar is based on the following reference \cite pietrucci09jctc. The authors of +this paper use the set of distances from the anti parallel beta sheet configurations to measure the number of segments that have an configuration that resemebles an anti paralel beta sheet. This is done by calculating the following sum of functions of the rmsd distances: @@ -50,24 +50,24 @@ the following sum of functions of the rmsd distances: s = \sum_i \frac{ 1 - \left(\frac{r_i-d_0}{r_0}\right)^n } { 1 - \left(\frac{r_i-d_0}{r_0}\right)^m } \f] -where the sum runs over all possible segments of antiparallel beta sheet. By default the +where the sum runs over all possible segments of antiparallel beta sheet. By default the NN, MM and D_0 parameters are set equal to those used in \cite pietrucci09jctc. The R_0 parameter must be set by the user - the value used in \cite pietrucci09jctc was 0.08 nm. If you change the function in the above sum you can calculate quantities such as the average -distance from a purely configuration composed of pure anti-parallel beta sheets or the distance between the set of -residues that is closest to an anti-parallel beta sheet and the reference configuration. To do these sorts of +distance from a purely configuration composed of pure anti-parallel beta sheets or the distance between the set of +residues that is closest to an anti-parallel beta sheet and the reference configuration. To do these sorts of calculations you can use the AVERAGE and MIN keywords. In addition you can use the LESS_THAN keyword if you would like to change the form of the switching function. If you use any of these -options you no longer need to specify NN, R_0, MM and D_0. +options you no longer need to specify NN, R_0, MM and D_0. -Please be aware that for codes like gromacs you must ensure that plumed +Please be aware that for codes like gromacs you must ensure that plumed reconstructs the chains involved in your CV when you calculate this CV using anthing other than TYPE=DRMSD. For more details as to how to do this see \ref WHOLEMOLECULES. \par Examples -The following input calculates the number of six residue segments of +The following input calculates the number of six residue segments of protein that are in an antiparallel beta sheet configuration. \verbatim @@ -83,83 +83,83 @@ class AntibetaRMSD : public SecondaryStructureRMSD { public: static void registerKeywords( Keywords& keys ); explicit AntibetaRMSD(const ActionOptions&); -}; +}; PLUMED_REGISTER_ACTION(AntibetaRMSD,"ANTIBETARMSD") -void AntibetaRMSD::registerKeywords( Keywords& keys ){ +void AntibetaRMSD::registerKeywords( Keywords& keys ) { SecondaryStructureRMSD::registerKeywords( keys ); keys.add("compulsory","STYLE","all","Antiparallel beta sheets can either form in a single chain or from a pair of chains. If STYLE=all all " - "chain configuration with the appropriate geometry are counted. If STYLE=inter " - "only sheet-like configurations involving two chains are counted, while if STYLE=intra " - "only sheet-like configurations involving a single chain are counted"); + "chain configuration with the appropriate geometry are counted. If STYLE=inter " + "only sheet-like configurations involving two chains are counted, while if STYLE=intra " + "only sheet-like configurations involving a single chain are counted"); keys.use("STRANDS_CUTOFF"); } AntibetaRMSD::AntibetaRMSD(const ActionOptions&ao): -Action(ao), -SecondaryStructureRMSD(ao) + Action(ao), + SecondaryStructureRMSD(ao) { // read in the backbone atoms std::vector<unsigned> chains; readBackboneAtoms( "protein", chains ); - bool intra_chain(false), inter_chain(false); + bool intra_chain(false), inter_chain(false); std::string style; parse("STYLE",style); - if( style=="all" ){ - intra_chain=true; inter_chain=true; - } else if( style=="inter"){ - intra_chain=false; inter_chain=true; - } else if( style=="intra"){ - intra_chain=true; inter_chain=false; + if( style=="all" ) { + intra_chain=true; inter_chain=true; + } else if( style=="inter") { + intra_chain=false; inter_chain=true; + } else if( style=="intra") { + intra_chain=true; inter_chain=false; } else { - error( style + " is not a valid directive for the STYLE keyword"); + error( style + " is not a valid directive for the STYLE keyword"); } - + // Align the atoms based on the positions of these two atoms setAtomsFromStrands( 6, 21 ); // This constructs all conceivable sections of antibeta sheet in the backbone of the chains - if( intra_chain ){ + if( intra_chain ) { unsigned nres, nprevious=0; std::vector<unsigned> nlist(30); - for(unsigned i=0;i<chains.size();++i){ - if( chains[i]<40 ) error("segment of backbone is not long enough to form an antiparallel beta hairpin. Each backbone fragment must contain a minimum of 8 residues"); - // Loop over all possible triples in each 8 residue segment of protein - nres=chains[i]/5; - if( chains[i]%5!=0 ) error("backbone segment received does not contain a multiple of five residues"); - for(unsigned ires=0;ires<nres-7;ires++){ - for(unsigned jres=ires+7;jres<nres;jres++){ - for(unsigned k=0;k<15;++k){ - nlist[k]=nprevious + ires*5+k; - nlist[k+15]=nprevious + (jres-2)*5+k; - } - addColvar( nlist ); - } - } - nprevious+=chains[i]; + for(unsigned i=0; i<chains.size(); ++i) { + if( chains[i]<40 ) error("segment of backbone is not long enough to form an antiparallel beta hairpin. Each backbone fragment must contain a minimum of 8 residues"); + // Loop over all possible triples in each 8 residue segment of protein + nres=chains[i]/5; + if( chains[i]%5!=0 ) error("backbone segment received does not contain a multiple of five residues"); + for(unsigned ires=0; ires<nres-7; ires++) { + for(unsigned jres=ires+7; jres<nres; jres++) { + for(unsigned k=0; k<15; ++k) { + nlist[k]=nprevious + ires*5+k; + nlist[k+15]=nprevious + (jres-2)*5+k; + } + addColvar( nlist ); + } + } + nprevious+=chains[i]; } } - if( inter_chain ){ - if( chains.size()==1 && style!="all" ) error("there is only one chain defined so cannot use inter_chain option"); - unsigned iprev,jprev,inres,jnres; std::vector<unsigned> nlist(30); - for(unsigned ichain=1;ichain<chains.size();++ichain){ - iprev=0; for(unsigned i=0;i<ichain;++i) iprev+=chains[i]; - inres=chains[ichain]/5; - if( chains[ichain]%5!=0 ) error("backbone segment received does not contain a multiple of five residues"); - for(unsigned ires=0;ires<inres-2;++ires){ - for(unsigned jchain=0;jchain<ichain;++jchain){ - jprev=0; for(unsigned i=0;i<jchain;++i) jprev+=chains[i]; - jnres=chains[jchain]/5; - if( chains[jchain]%5!=0 ) error("backbone segment received does not contain a multiple of five residues"); - for(unsigned jres=0;jres<jnres-2;++jres){ - for(unsigned k=0;k<15;++k){ - nlist[k]=iprev+ ires*5+k; - nlist[k+15]=jprev+ jres*5+k; - } - addColvar( nlist ); - } + if( inter_chain ) { + if( chains.size()==1 && style!="all" ) error("there is only one chain defined so cannot use inter_chain option"); + unsigned iprev,jprev,inres,jnres; std::vector<unsigned> nlist(30); + for(unsigned ichain=1; ichain<chains.size(); ++ichain) { + iprev=0; for(unsigned i=0; i<ichain; ++i) iprev+=chains[i]; + inres=chains[ichain]/5; + if( chains[ichain]%5!=0 ) error("backbone segment received does not contain a multiple of five residues"); + for(unsigned ires=0; ires<inres-2; ++ires) { + for(unsigned jchain=0; jchain<ichain; ++jchain) { + jprev=0; for(unsigned i=0; i<jchain; ++i) jprev+=chains[i]; + jnres=chains[jchain]/5; + if( chains[jchain]%5!=0 ) error("backbone segment received does not contain a multiple of five residues"); + for(unsigned jres=0; jres<jnres-2; ++jres) { + for(unsigned k=0; k<15; ++k) { + nlist[k]=iprev+ ires*5+k; + nlist[k+15]=jprev+ jres*5+k; } - } - } + addColvar( nlist ); + } + } + } + } } // Build the reference structure ( in angstroms ) @@ -196,7 +196,7 @@ SecondaryStructureRMSD(ao) reference[29]=Vector( 1.899, -4.545, -1.102); // O // Store the secondary structure ( last number makes sure we convert to internal units nm ) - setSecondaryStructure( reference, 0.17/atoms.getUnits().getLength(), 0.1/atoms.getUnits().getLength() ); + setSecondaryStructure( reference, 0.17/atoms.getUnits().getLength(), 0.1/atoms.getUnits().getLength() ); } } diff --git a/src/secondarystructure/ParabetaRMSD.cpp b/src/secondarystructure/ParabetaRMSD.cpp index b4849062d..fe8740864 100644 --- a/src/secondarystructure/ParabetaRMSD.cpp +++ b/src/secondarystructure/ParabetaRMSD.cpp @@ -31,18 +31,18 @@ namespace secondarystructure { /* Probe the parallel beta sheet content of your protein structure. -Two protein segments containing three continguous residues can form a parallel beta sheet. -Although if the two segments are part of the same protein chain they must be separated by -a minimum of 3 residues to make room for the turn. This colvar thus generates the set of -all possible six residue sections that could conceivably form a parallel beta sheet +Two protein segments containing three continguous residues can form a parallel beta sheet. +Although if the two segments are part of the same protein chain they must be separated by +a minimum of 3 residues to make room for the turn. This colvar thus generates the set of +all possible six residue sections that could conceivably form a parallel beta sheet and calculates the RMSD distance between the configuration in which the residues find themselves -and an idealized parallel beta sheet structure. These distances can be calculated by either +and an idealized parallel beta sheet structure. These distances can be calculated by either aligning the instantaneous structure with the reference structure and measuring each atomic displacement or by calculating differences between the set of interatomic -distances in the reference and instantaneous structures. +distances in the reference and instantaneous structures. -This colvar is based on the following reference \cite pietrucci09jctc. The authors of -this paper use the set of distances from the parallel beta sheet configurations to measure +This colvar is based on the following reference \cite pietrucci09jctc. The authors of +this paper use the set of distances from the parallel beta sheet configurations to measure the number of segments whose configuration resembles a parallel beta sheet. This is done by calculating the following sum of functions of the rmsd distances: @@ -50,24 +50,24 @@ the following sum of functions of the rmsd distances: s = \sum_i \frac{ 1 - \left(\frac{r_i-d_0}{r_0}\right)^n } { 1 - \left(\frac{r_i-d_0}{r_0}\right)^m } \f] -where the sum runs over all possible segments of parallel beta sheet. By default the +where the sum runs over all possible segments of parallel beta sheet. By default the NN, MM and D_0 parameters are set equal to those used in \cite pietrucci09jctc. The R_0 parameter must be set by the user - the value used in \cite pietrucci09jctc was 0.08 nm. If you change the function in the above sum you can calculate quantities such as the average -distance from a structure composed of only parallel beta sheets or the distance between the set of -residues that is closest to a parallel beta sheet and the reference configuration. To do these sorts of +distance from a structure composed of only parallel beta sheets or the distance between the set of +residues that is closest to a parallel beta sheet and the reference configuration. To do these sorts of calculations you can use the AVERAGE and MIN keywords. In addition you can use the LESS_THAN keyword if you would like to change the form of the switching function. If you use any of these -options you no longer need to specify NN, R_0, MM and D_0. +options you no longer need to specify NN, R_0, MM and D_0. -Please be aware that for codes like gromacs you must ensure that plumed +Please be aware that for codes like gromacs you must ensure that plumed reconstructs the chains involved in your CV when you calculate this CV using anthing other than TYPE=DRMSD. For more details as to how to do this see \ref WHOLEMOLECULES. \par Examples -The following input calculates the number of six residue segments of +The following input calculates the number of six residue segments of protein that are in an parallel beta sheet configuration. \verbatim @@ -83,84 +83,84 @@ class ParabetaRMSD : public SecondaryStructureRMSD { public: static void registerKeywords( Keywords& keys ); explicit ParabetaRMSD(const ActionOptions&); -}; +}; PLUMED_REGISTER_ACTION(ParabetaRMSD,"PARABETARMSD") -void ParabetaRMSD::registerKeywords( Keywords& keys ){ +void ParabetaRMSD::registerKeywords( Keywords& keys ) { SecondaryStructureRMSD::registerKeywords( keys ); keys.add("compulsory","STYLE","all","Parallel beta sheets can either form in a single chain or from a pair of chains. If STYLE=all all " - "chain configuration with the appropriate geometry are counted. If STYLE=inter " - "only sheet-like configurations involving two chains are counted, while if STYLE=intra " - "only sheet-like configurations involving a single chain are counted"); + "chain configuration with the appropriate geometry are counted. If STYLE=inter " + "only sheet-like configurations involving two chains are counted, while if STYLE=intra " + "only sheet-like configurations involving a single chain are counted"); keys.use("STRANDS_CUTOFF"); } ParabetaRMSD::ParabetaRMSD(const ActionOptions&ao): -Action(ao), -SecondaryStructureRMSD(ao) + Action(ao), + SecondaryStructureRMSD(ao) { // read in the backbone atoms std::vector<unsigned> chains; readBackboneAtoms( "protein", chains ); - bool intra_chain(false), inter_chain(false); + bool intra_chain(false), inter_chain(false); std::string style; parse("STYLE",style); - if( style=="all" ){ - intra_chain=true; inter_chain=true; - } else if( style=="inter"){ - intra_chain=false; inter_chain=true; - } else if( style=="intra"){ - intra_chain=true; inter_chain=false; + if( style=="all" ) { + intra_chain=true; inter_chain=true; + } else if( style=="inter") { + intra_chain=false; inter_chain=true; + } else if( style=="intra") { + intra_chain=true; inter_chain=false; } else { - error( style + " is not a valid directive for the STYLE keyword"); + error( style + " is not a valid directive for the STYLE keyword"); } // Align the atoms based on the positions of these two atoms setAtomsFromStrands( 6, 21 ); // This constructs all conceivable sections of antibeta sheet in the backbone of the chains - if( intra_chain ){ + if( intra_chain ) { unsigned nres, nprevious=0; std::vector<unsigned> nlist(30); - for(unsigned i=0;i<chains.size();++i){ - if( chains[i]<40 ) error("segment of backbone is not long enough to form an antiparallel beta hairpin. Each backbone fragment must contain a minimum of 8 residues"); - // Loop over all possible triples in each 8 residue segment of protein - nres=chains[i]/5; - if( chains[i]%5!=0 ) error("backbone segment received does not contain a multiple of five residues"); - for(unsigned ires=0;ires<nres-8;ires++){ - for(unsigned jres=ires+6;jres<nres-2;jres++){ - for(unsigned k=0;k<15;++k){ - nlist[k]=nprevious + ires*5+k; - nlist[k+15]=nprevious + jres*5+k; - } - addColvar( nlist ); - } - } - nprevious+=chains[i]; + for(unsigned i=0; i<chains.size(); ++i) { + if( chains[i]<40 ) error("segment of backbone is not long enough to form an antiparallel beta hairpin. Each backbone fragment must contain a minimum of 8 residues"); + // Loop over all possible triples in each 8 residue segment of protein + nres=chains[i]/5; + if( chains[i]%5!=0 ) error("backbone segment received does not contain a multiple of five residues"); + for(unsigned ires=0; ires<nres-8; ires++) { + for(unsigned jres=ires+6; jres<nres-2; jres++) { + for(unsigned k=0; k<15; ++k) { + nlist[k]=nprevious + ires*5+k; + nlist[k+15]=nprevious + jres*5+k; + } + addColvar( nlist ); + } + } + nprevious+=chains[i]; } } // This constructs all conceivable sections of antibeta sheet that form between chains - if( inter_chain ){ - if( chains.size()==1 && style!="all" ) error("there is only one chain defined so cannot use inter_chain option"); - unsigned iprev,jprev,inres,jnres; std::vector<unsigned> nlist(30); - for(unsigned ichain=1;ichain<chains.size();++ichain){ - iprev=0; for(unsigned i=0;i<ichain;++i) iprev+=chains[i]; - inres=chains[ichain]/5; - if( chains[ichain]%5!=0 ) error("backbone segment received does not contain a multiple of five residues"); - for(unsigned ires=0;ires<inres-2;++ires){ - for(unsigned jchain=0;jchain<ichain;++jchain){ - jprev=0; for(unsigned i=0;i<jchain;++i) jprev+=chains[i]; - jnres=chains[jchain]/5; - if( chains[jchain]%5!=0 ) error("backbone segment received does not contain a multiple of five residues"); - for(unsigned jres=0;jres<jnres-2;++jres){ - for(unsigned k=0;k<15;++k){ - nlist[k]=iprev + ires*5+k; - nlist[k+15]=jprev + jres*5+k; - } - addColvar( nlist ); - } + if( inter_chain ) { + if( chains.size()==1 && style!="all" ) error("there is only one chain defined so cannot use inter_chain option"); + unsigned iprev,jprev,inres,jnres; std::vector<unsigned> nlist(30); + for(unsigned ichain=1; ichain<chains.size(); ++ichain) { + iprev=0; for(unsigned i=0; i<ichain; ++i) iprev+=chains[i]; + inres=chains[ichain]/5; + if( chains[ichain]%5!=0 ) error("backbone segment received does not contain a multiple of five residues"); + for(unsigned ires=0; ires<inres-2; ++ires) { + for(unsigned jchain=0; jchain<ichain; ++jchain) { + jprev=0; for(unsigned i=0; i<jchain; ++i) jprev+=chains[i]; + jnres=chains[jchain]/5; + if( chains[jchain]%5!=0 ) error("backbone segment received does not contain a multiple of five residues"); + for(unsigned jres=0; jres<jnres-2; ++jres) { + for(unsigned k=0; k<15; ++k) { + nlist[k]=iprev + ires*5+k; + nlist[k+15]=jprev + jres*5+k; } - } - } + addColvar( nlist ); + } + } + } + } } // Build the reference structure ( in angstroms ) @@ -196,7 +196,7 @@ SecondaryStructureRMSD(ao) reference[28]=Vector(-0.229, 4.791, 1.038); // C reference[29]=Vector( 0.523, 5.771, 0.996); // O // Store the secondary structure ( last number makes sure we convert to internal units nm ) - setSecondaryStructure( reference, 0.17/atoms.getUnits().getLength(), 0.1/atoms.getUnits().getLength() ); + setSecondaryStructure( reference, 0.17/atoms.getUnits().getLength(), 0.1/atoms.getUnits().getLength() ); reference[0]=Vector(-1.439, -5.122, -1.144); // N i reference[1]=Vector(-0.816, -3.803, -1.013); // CA diff --git a/src/secondarystructure/SecondaryStructureRMSD.cpp b/src/secondarystructure/SecondaryStructureRMSD.cpp index d2f902796..8c51dc8ed 100644 --- a/src/secondarystructure/SecondaryStructureRMSD.cpp +++ b/src/secondarystructure/SecondaryStructureRMSD.cpp @@ -29,33 +29,33 @@ #include "reference/SingleDomainRMSD.h" namespace PLMD { -namespace secondarystructure{ +namespace secondarystructure { -void SecondaryStructureRMSD::registerKeywords( Keywords& keys ){ +void SecondaryStructureRMSD::registerKeywords( Keywords& keys ) { Action::registerKeywords( keys ); ActionWithValue::registerKeywords( keys ); ActionAtomistic::registerKeywords( keys ); keys.add("residues","RESIDUES","this command is used to specify the set of residues that could conceivably form part of the secondary structure. " - "It is possible to use residues numbers as the various chains and residues should have been identified else using an instance of the " - "\\ref MOLINFO action. If you wish to use all the residues from all the chains in your system you can do so by " - "specifying all. Alternatively, if you wish to use a subset of the residues you can specify the particular residues " - "you are interested in as a list of numbers. Please be aware that to form secondary structure elements your chain " - "must contain at least N residues, where N is dependent on the particular secondary structure you are interested in. " - "As such if you define portions of the chain with fewer than N residues the code will crash."); + "It is possible to use residues numbers as the various chains and residues should have been identified else using an instance of the " + "\\ref MOLINFO action. If you wish to use all the residues from all the chains in your system you can do so by " + "specifying all. Alternatively, if you wish to use a subset of the residues you can specify the particular residues " + "you are interested in as a list of numbers. Please be aware that to form secondary structure elements your chain " + "must contain at least N residues, where N is dependent on the particular secondary structure you are interested in. " + "As such if you define portions of the chain with fewer than N residues the code will crash."); keys.add("compulsory","TYPE","DRMSD","the manner in which RMSD alignment is performed. Should be OPTIMAL, SIMPLE or DRMSD. " - "For more details on the OPTIMAL and SIMPLE methods see \\ref RMSD. For more details on the " - "DRMSD method see \\ref DRMSD."); + "For more details on the OPTIMAL and SIMPLE methods see \\ref RMSD. For more details on the " + "DRMSD method see \\ref DRMSD."); keys.add("compulsory","R_0","The r_0 parameter of the switching function."); keys.add("compulsory","D_0","0.0","The d_0 parameter of the switching function"); keys.add("compulsory","NN","8","The n parameter of the switching function"); keys.add("compulsory","MM","12","The m parameter of the switching function"); keys.reserve("optional","STRANDS_CUTOFF","If in a segment of protein the two strands are further apart then the calculation " - "of the actual RMSD is skipped as the structure is very far from being beta-sheet like. " - "This keyword speeds up the calculation enormously when you are using the LESS_THAN option. " - "However, if you are using some other option, then this cannot be used"); + "of the actual RMSD is skipped as the structure is very far from being beta-sheet like. " + "This keyword speeds up the calculation enormously when you are using the LESS_THAN option. " + "However, if you are using some other option, then this cannot be used"); keys.addFlag("VERBOSE",false,"write a more detailed output"); keys.add("hidden","NL_STRIDE","the frequency with which the neighbor list should be updated. Between neighbour list update steps all quantities " - "that contributed less than TOL at the previous neighbor list update step are ignored."); + "that contributed less than TOL at the previous neighbor list update step are ignored."); ActionWithVessel::registerKeywords( keys ); keys.use("LESS_THAN"); keys.use("MIN"); keys.use("ALT_MIN"); keys.use("LOWEST"); keys.use("HIGHEST"); keys.setComponentsIntroduction("By default this Action calculates the number of structural units that are within a certain " @@ -66,26 +66,26 @@ void SecondaryStructureRMSD::registerKeywords( Keywords& keys ){ "from the table below. Please note that you can use the LESS_THAN keyword more than once. The resulting " "components will be labelled <em>label</em>.lessthan-1, <em>label</em>.lessthan-2 and so on unless you " "exploit the fact that these labels are customizable. In particular, by using the LABEL keyword in the " - "description of you LESS_THAN function you can set name of the component that you are calculating"); + "description of you LESS_THAN function you can set name of the component that you are calculating"); } SecondaryStructureRMSD::SecondaryStructureRMSD(const ActionOptions&ao): -Action(ao), -ActionAtomistic(ao), -ActionWithValue(ao), -ActionWithVessel(ao), -align_strands(false), -s_cutoff2(0), -align_atom_1(0), -align_atom_2(0) + Action(ao), + ActionAtomistic(ao), + ActionWithValue(ao), + ActionWithVessel(ao), + align_strands(false), + s_cutoff2(0), + align_atom_1(0), + align_atom_2(0) { parse("TYPE",alignType); log.printf(" distances from secondary structure elements are calculated using %s algorithm\n",alignType.c_str() ); log<<" Bibliography "<<plumed.cite("Pietrucci and Laio, J. Chem. Theory Comput. 5, 2197 (2009)"); log<<"\n"; - parseFlag("VERBOSE",verbose_output); + parseFlag("VERBOSE",verbose_output); - if( keywords.exists("STRANDS_CUTOFF") ){ + if( keywords.exists("STRANDS_CUTOFF") ) { double s_cutoff = 0; parse("STRANDS_CUTOFF",s_cutoff); align_strands=true; if( s_cutoff>0) log.printf(" ignoring contributions from strands that are more than %f apart\n",s_cutoff); @@ -93,95 +93,95 @@ align_atom_2(0) } } -SecondaryStructureRMSD::~SecondaryStructureRMSD(){ - for(unsigned i=0;i<references.size();++i) delete references[i]; +SecondaryStructureRMSD::~SecondaryStructureRMSD() { + for(unsigned i=0; i<references.size(); ++i) delete references[i]; } -void SecondaryStructureRMSD::turnOnDerivatives(){ +void SecondaryStructureRMSD::turnOnDerivatives() { ActionWithValue::turnOnDerivatives(); needsDerivatives(); } -void SecondaryStructureRMSD::setAtomsFromStrands( const unsigned& atom1, const unsigned& atom2 ){ - align_atom_1=atom1; align_atom_2=atom2; +void SecondaryStructureRMSD::setAtomsFromStrands( const unsigned& atom1, const unsigned& atom2 ) { + align_atom_1=atom1; align_atom_2=atom2; } -void SecondaryStructureRMSD::readBackboneAtoms( const std::string& moltype, std::vector<unsigned>& chain_lengths ){ +void SecondaryStructureRMSD::readBackboneAtoms( const std::string& moltype, std::vector<unsigned>& chain_lengths ) { std::vector<SetupMolInfo*> moldat=plumed.getActionSet().select<SetupMolInfo*>(); if( moldat.size()==0 ) error("Unable to find MOLINFO in input"); std::vector<std::string> resstrings; parseVector( "RESIDUES", resstrings ); - if( !verbose_output ){ - if(resstrings[0]=="all"){ - log.printf(" examining all possible secondary structure combinations\n"); - } else { - log.printf(" examining secondary structure in residue positions : %s \n",resstrings[0].c_str() ); - for(unsigned i=1;i<resstrings.size();++i) log.printf(", %s",resstrings[i].c_str() ); - log.printf("\n"); - } + if( !verbose_output ) { + if(resstrings[0]=="all") { + log.printf(" examining all possible secondary structure combinations\n"); + } else { + log.printf(" examining secondary structure in residue positions : %s \n",resstrings[0].c_str() ); + for(unsigned i=1; i<resstrings.size(); ++i) log.printf(", %s",resstrings[i].c_str() ); + log.printf("\n"); + } } std::vector< std::vector<AtomNumber> > backatoms; moldat[0]->getBackbone( resstrings, moltype, backatoms ); chain_lengths.resize( backatoms.size() ); - for(unsigned i=0;i<backatoms.size();++i){ - chain_lengths[i]=backatoms[i].size(); - for(unsigned j=0;j<backatoms[i].size();++j) all_atoms.push_back( backatoms[i][j] ); + for(unsigned i=0; i<backatoms.size(); ++i) { + chain_lengths[i]=backatoms[i].size(); + for(unsigned j=0; j<backatoms[i].size(); ++j) all_atoms.push_back( backatoms[i][j] ); } ActionAtomistic::requestAtoms( all_atoms ); forcesToApply.resize( getNumberOfDerivatives() ); } -void SecondaryStructureRMSD::addColvar( const std::vector<unsigned>& newatoms ){ +void SecondaryStructureRMSD::addColvar( const std::vector<unsigned>& newatoms ) { if( colvar_atoms.size()>0 ) plumed_assert( colvar_atoms[0].size()==newatoms.size() ); - if( verbose_output ){ - log.printf(" Secondary structure segment %u contains atoms : ", static_cast<unsigned>(colvar_atoms.size()+1)); - for(unsigned i=0;i<newatoms.size();++i) log.printf("%d ",all_atoms[newatoms[i]].serial() ); - log.printf("\n"); + if( verbose_output ) { + log.printf(" Secondary structure segment %u contains atoms : ", static_cast<unsigned>(colvar_atoms.size()+1)); + for(unsigned i=0; i<newatoms.size(); ++i) log.printf("%d ",all_atoms[newatoms[i]].serial() ); + log.printf("\n"); } addTaskToList( colvar_atoms.size() ); colvar_atoms.push_back( newatoms ); } -void SecondaryStructureRMSD::setSecondaryStructure( std::vector<Vector>& structure, double bondlength, double units ){ +void SecondaryStructureRMSD::setSecondaryStructure( std::vector<Vector>& structure, double bondlength, double units ) { // If we are in natural units get conversion factor from nm into natural length units - if( plumed.getAtoms().usingNaturalUnits() ){ - error("cannot use this collective variable when using natural units"); + if( plumed.getAtoms().usingNaturalUnits() ) { + error("cannot use this collective variable when using natural units"); } - plumed_massert( !(align_strands && align_atom_1==0 && align_atom_2==0), "you must use setAtomsFromStrands with strands cutoff"); + plumed_massert( !(align_strands && align_atom_1==0 && align_atom_2==0), "you must use setAtomsFromStrands with strands cutoff"); // Convert into correct units - for(unsigned i=0;i<structure.size();++i){ - structure[i][0]*=units; structure[i][1]*=units; structure[i][2]*=units; + for(unsigned i=0; i<structure.size(); ++i) { + structure[i][0]*=units; structure[i][1]*=units; structure[i][2]*=units; } - if( references.size()==0 ){ - readVesselKeywords(); - if( getNumberOfVessels()==0 ){ - double r0; parse("R_0",r0); double d0; parse("D_0",d0); - int nn; parse("NN",nn); int mm; parse("MM",mm); - std::ostringstream ostr; - ostr<<"RATIONAL R_0="<<r0<<" D_0="<<d0<<" NN="<<nn<<" MM="<<mm; - std::string input=ostr.str(); addVessel( "LESS_THAN", input, -1 ); // -1 here means that this value will be named getLabel() - readVesselKeywords(); // This makes sure resizing is done - } + if( references.size()==0 ) { + readVesselKeywords(); + if( getNumberOfVessels()==0 ) { + double r0; parse("R_0",r0); double d0; parse("D_0",d0); + int nn; parse("NN",nn); int mm; parse("MM",mm); + std::ostringstream ostr; + ostr<<"RATIONAL R_0="<<r0<<" D_0="<<d0<<" NN="<<nn<<" MM="<<mm; + std::string input=ostr.str(); addVessel( "LESS_THAN", input, -1 ); // -1 here means that this value will be named getLabel() + readVesselKeywords(); // This makes sure resizing is done + } } // Set the reference structure - references.push_back( metricRegister().create<SingleDomainRMSD>( alignType ) ); + references.push_back( metricRegister().create<SingleDomainRMSD>( alignType ) ); unsigned nn=references.size()-1; std::vector<double> align( structure.size(), 1.0 ), displace( structure.size(), 1.0 ); - references[nn]->setBoundsOnDistances( true , bondlength ); // We always use pbc + references[nn]->setBoundsOnDistances( true, bondlength ); // We always use pbc references[nn]->setReferenceAtoms( structure, align, displace ); // references[nn]->setNumberOfAtoms( structure.size() ); // And prepare the task list deactivateAllTasks(); - for(unsigned i=0;i<getFullNumberOfTasks();++i) taskFlags[i]=1; - lockContributors(); + for(unsigned i=0; i<getFullNumberOfTasks(); ++i) taskFlags[i]=1; + lockContributors(); } -void SecondaryStructureRMSD::calculate(){ +void SecondaryStructureRMSD::calculate() { runAllTasks(); } @@ -189,57 +189,57 @@ void SecondaryStructureRMSD::performTask( const unsigned& task_index, const unsi // Retrieve the positions std::vector<Vector> pos( references[0]->getNumberOfAtoms() ); const unsigned n=pos.size(); - for(unsigned i=0;i<n;++i) pos[i]=ActionAtomistic::getPosition( getAtomIndex(current,i) ); + for(unsigned i=0; i<n; ++i) pos[i]=ActionAtomistic::getPosition( getAtomIndex(current,i) ); // This does strands cutoff - Vector distance=pbcDistance( pos[align_atom_1],pos[align_atom_2] ); - if( s_cutoff2>0 ){ - if( distance.modulo2()>s_cutoff2 ){ - myvals.setValue( 0, 0.0 ); - return; - } + Vector distance=pbcDistance( pos[align_atom_1],pos[align_atom_2] ); + if( s_cutoff2>0 ) { + if( distance.modulo2()>s_cutoff2 ) { + myvals.setValue( 0, 0.0 ); + return; + } } // This aligns the two strands if this is required - if( alignType!="DRMSD" && align_strands ){ - Vector origin_old, origin_new; origin_old=pos[align_atom_2]; - origin_new=pos[align_atom_1]+distance; - for(unsigned i=15;i<30;++i){ - pos[i]+=( origin_new - origin_old ); - } + if( alignType!="DRMSD" && align_strands ) { + Vector origin_old, origin_new; origin_old=pos[align_atom_2]; + origin_new=pos[align_atom_1]+distance; + for(unsigned i=15; i<30; ++i) { + pos[i]+=( origin_new - origin_old ); + } } // Create a holder for the derivatives ReferenceValuePack mypack( 0, pos.size(), myvals ); mypack.setValIndex( 1 ); - for(unsigned i=0;i<n;++i) mypack.setAtomIndex( i, getAtomIndex(current,i) ); + for(unsigned i=0; i<n; ++i) mypack.setAtomIndex( i, getAtomIndex(current,i) ); // And now calculate the RMSD - const Pbc& pbc=getPbc(); - unsigned closest=0; + const Pbc& pbc=getPbc(); + unsigned closest=0; double r = references[0]->calculate( pos, pbc, mypack, false ); const unsigned rs = references.size(); - for(unsigned i=1;i<rs;++i){ + for(unsigned i=1; i<rs; ++i) { mypack.setValIndex( i+1 ); double nr=references[i]->calculate( pos, pbc, mypack, false ); - if( nr<r ){ closest=i; r=nr; } + if( nr<r ) { closest=i; r=nr; } } // Transfer everything to the value myvals.setValue( 0, 1.0 ); myvals.setValue( 1, r ); if( closest>0 ) mypack.moveDerivatives( closest+1, 1 ); - if( !mypack.virialWasSet() ){ + if( !mypack.virialWasSet() ) { Tensor vir; const unsigned cacs = colvar_atoms[current].size(); - for(unsigned i=0;i<cacs;++i){ - vir+=(-1.0*Tensor( pos[i], mypack.getAtomDerivative(i) )); - } + for(unsigned i=0; i<cacs; ++i) { + vir+=(-1.0*Tensor( pos[i], mypack.getAtomDerivative(i) )); + } mypack.setValIndex(1); mypack.addBoxDerivatives( vir ); } return; } -void SecondaryStructureRMSD::apply(){ +void SecondaryStructureRMSD::apply() { if( getForcesFromVessels( forcesToApply ) ) setForcesOnAtoms( forcesToApply ); } diff --git a/src/secondarystructure/SecondaryStructureRMSD.h b/src/secondarystructure/SecondaryStructureRMSD.h index 7acc87a2a..336d3bec8 100644 --- a/src/secondarystructure/SecondaryStructureRMSD.h +++ b/src/secondarystructure/SecondaryStructureRMSD.h @@ -35,7 +35,7 @@ namespace secondarystructure { /// Base action for calculating things like AlphRMSD, AntibetaRMSD, etc -class SecondaryStructureRMSD : +class SecondaryStructureRMSD : public ActionAtomistic, public ActionWithValue, public vesselbase::ActionWithVessel @@ -76,9 +76,9 @@ public: unsigned getNumberOfQuantities() const ; void turnOnDerivatives(); void calculate(); - void performTask( const unsigned& , const unsigned& , MultiValue& ) const ; + void performTask( const unsigned&, const unsigned&, MultiValue& ) const ; void apply(); - bool isPeriodic(){ return false; } + bool isPeriodic() { return false; } }; inline @@ -88,12 +88,12 @@ unsigned SecondaryStructureRMSD::getNumberOfQuantities() const { inline -unsigned SecondaryStructureRMSD::getNumberOfFunctionsInAction(){ +unsigned SecondaryStructureRMSD::getNumberOfFunctionsInAction() { return colvar_atoms.size(); } inline -unsigned SecondaryStructureRMSD::getNumberOfDerivatives(){ +unsigned SecondaryStructureRMSD::getNumberOfDerivatives() { return 3*getNumberOfAtoms()+9; } diff --git a/src/setup/Load.cpp b/src/setup/Load.cpp index 5505493ba..93f9d39b8 100644 --- a/src/setup/Load.cpp +++ b/src/setup/Load.cpp @@ -26,8 +26,8 @@ using namespace std; -namespace PLMD{ -namespace setup{ +namespace PLMD { +namespace setup { //+PLUMEDOC GENERIC LOAD /* @@ -88,7 +88,7 @@ PRINT ARG=d,d2 FILE=compare-them This will allow to make quick tests while developing your own variables. Of course, after your implementation is ready you might -want to add it to the PLUMED source tree and recompile +want to add it to the PLUMED source tree and recompile the whole PLUMED. @@ -105,14 +105,14 @@ public: PLUMED_REGISTER_ACTION(Load,"LOAD") -void Load::registerKeywords( Keywords& keys ){ +void Load::registerKeywords( Keywords& keys ) { ActionSetup::registerKeywords(keys); keys.add("compulsory","FILE","file to be loaded"); } Load::Load(const ActionOptions&ao): -Action(ao), -ActionSetup(ao) + Action(ao), + ActionSetup(ao) { std::string f; parse("FILE",f); diff --git a/src/setup/MolInfo.cpp b/src/setup/MolInfo.cpp index ded72a615..ed2ca421c 100644 --- a/src/setup/MolInfo.cpp +++ b/src/setup/MolInfo.cpp @@ -22,8 +22,8 @@ #include "core/ActionRegister.h" #include "core/SetupMolInfo.h" -namespace PLMD{ -namespace setup{ +namespace PLMD { +namespace setup { //+PLUMEDOC TOPOLOGY MOLINFO /* @@ -34,7 +34,7 @@ or as a set of lists of atoms that describe the various chains in your system. I is used plumed the MOLINFO command will endeavor to recognize the various chains and residues that make up the molecules in your system using the chainIDs and resnumbers from the pdb file. You can then use this information in later commands to specify atom lists in terms residues. For example -using this command you can find the backbone atoms in your structure automatically. +using this command you can find the backbone atoms in your structure automatically. \warning Please be aware that the pdb parser in plumed is far from perfect. You should thus check the log file @@ -96,10 +96,10 @@ with the same name. This means that it is also possible to pick single atoms usi \warning If a residue-chain is repeated twice in the reference pdb only the first entry will be selected. \bug At the moment the HA1 atoms in a GLY residues are treated as if they are the CB atoms. This may or -may not be true - GLY is problematic for secondary structure residues as it is achiral. +may not be true - GLY is problematic for secondary structure residues as it is achiral. -\bug If you use WHOLEMOLECULES RESIDUES=1-10 for a 18 amino acid protein -( 18 amino acids + 2 terminal groups = 20 residues ) the code will fail as it will not be able to +\bug If you use WHOLEMOLECULES RESIDUES=1-10 for a 18 amino acid protein +( 18 amino acids + 2 terminal groups = 20 residues ) the code will fail as it will not be able to interpret terminal residue 1. \par Examples @@ -109,7 +109,7 @@ are in the backbone of a protein to the ALPHARMSD CV. \verbatim MOLINFO STRUCTURE=reference.pdb -ALPHARMSD RESIDUES=all TYPE=DRMSD LESS_THAN={RATIONAL R_0=0.08 NN=8 MM=12} LABEL=a +ALPHARMSD RESIDUES=all TYPE=DRMSD LESS_THAN={RATIONAL R_0=0.08 NN=8 MM=12} LABEL=a \endverbatim (see also \ref ALPHARMSD) diff --git a/src/setup/Restart.cpp b/src/setup/Restart.cpp index cb46256d0..ffa4f46b1 100644 --- a/src/setup/Restart.cpp +++ b/src/setup/Restart.cpp @@ -27,8 +27,8 @@ using namespace std; -namespace PLMD{ -namespace setup{ +namespace PLMD { +namespace setup { //+PLUMEDOC GENERIC RESTART /* @@ -93,20 +93,20 @@ public: PLUMED_REGISTER_ACTION(Restart,"RESTART") -void Restart::registerKeywords( Keywords& keys ){ +void Restart::registerKeywords( Keywords& keys ) { ActionSetup::registerKeywords(keys); keys.addFlag("NO",false,"switch off restart - can be used to override the behavior of the MD engine"); } Restart::Restart(const ActionOptions&ao): -Action(ao), -ActionSetup(ao) + Action(ao), + ActionSetup(ao) { bool no=false; parseFlag("NO",no); bool md=plumed.getRestart(); log<<" MD code "<<(md?"did":"didn't")<<" require restart\n"; - if(no){ + if(no) { if(md) log<<" Switching off restart\n"; plumed.setRestart(false); log<<" Not restarting simulation: files will be backed up\n"; diff --git a/src/setup/Units.cpp b/src/setup/Units.cpp index 6b2ddeeee..1b4225d24 100644 --- a/src/setup/Units.cpp +++ b/src/setup/Units.cpp @@ -27,14 +27,14 @@ using namespace std; -namespace PLMD{ -namespace setup{ +namespace PLMD { +namespace setup { //+PLUMEDOC GENERIC UNITS /* This command sets the internal units for the code. A new unit can be set by either specifying how to convert from the plumed default unit into that new unit or by using -the shortcuts described below. This directive MUST appear at the BEGINNING of the +the shortcuts described below. This directive MUST appear at the BEGINNING of the plumed.dat file. The same units must be used througout the plumed.dat file. Notice that all input/output will then be made using the specified units. @@ -68,7 +68,7 @@ public: PLUMED_REGISTER_ACTION(Units,"UNITS") -void Units::registerKeywords( Keywords& keys ){ +void Units::registerKeywords( Keywords& keys ) { ActionSetup::registerKeywords(keys); keys.add("optional","LENGTH","the units of lengths. Either specify a conversion factor from the default, nm, or A (for angstroms) or um"); keys.add("optional","ENERGY","the units of energy. Either specify a conversion factor from the default, kj/mol, or use j/mol or kcal/mol"); @@ -79,8 +79,8 @@ void Units::registerKeywords( Keywords& keys ){ } Units::Units(const ActionOptions&ao): -Action(ao), -ActionSetup(ao) + Action(ao), + ActionSetup(ao) { PLMD::Units u; @@ -123,7 +123,7 @@ ActionSetup(ao) checkRead(); plumed.getAtoms().setUnits(u); - if(natural){ + if(natural) { log.printf(" using natural units\n"); } else { log.printf(" using physical units\n"); diff --git a/src/tools/Angle.cpp b/src/tools/Angle.cpp index 1b824be93..c3841e128 100644 --- a/src/tools/Angle.cpp +++ b/src/tools/Angle.cpp @@ -23,46 +23,46 @@ #include "Tools.h" #include <cmath> -namespace PLMD{ +namespace PLMD { -double Angle::compute(const Vector& v1,const Vector& v2)const{ - return std::acos(dotProduct(v1,v2)/(v1.modulo()*v2.modulo())); +double Angle::compute(const Vector& v1,const Vector& v2)const { + return std::acos(dotProduct(v1,v2)/(v1.modulo()*v2.modulo())); } -double Angle::compute(const Vector& v1,const Vector& v2,Vector& d1,Vector& d2)const{ - const double dp(dotProduct(v1,v2)); - const Vector& dp_dv1(v2); - const Vector& dp_dv2(v1); - const double sv1(v1.modulo2()); - const double sv2(v2.modulo2()); - const Vector dsv1_dv1(2*v1); - const Vector dsv2_dv2(2*v2); - const double nn(1.0/sqrt(sv1*sv2)); - const Vector dnn_dv1(-0.5*nn/sv1*dsv1_dv1); - const Vector dnn_dv2(-0.5*nn/sv2*dsv2_dv2); +double Angle::compute(const Vector& v1,const Vector& v2,Vector& d1,Vector& d2)const { + const double dp(dotProduct(v1,v2)); + const Vector& dp_dv1(v2); + const Vector& dp_dv2(v1); + const double sv1(v1.modulo2()); + const double sv2(v2.modulo2()); + const Vector dsv1_dv1(2*v1); + const Vector dsv2_dv2(2*v2); + const double nn(1.0/sqrt(sv1*sv2)); + const Vector dnn_dv1(-0.5*nn/sv1*dsv1_dv1); + const Vector dnn_dv2(-0.5*nn/sv2*dsv2_dv2); - const double dpnn(dp*nn); + const double dpnn(dp*nn); - if(dpnn>=1.0-epsilon){ - d1=Vector(0.0,0.0,0.0); - d2=Vector(0.0,0.0,0.0); - return 0.0; - } - if(dpnn<=-1.0+epsilon){ - d1=Vector(0.0,0.0,0.0); - d2=Vector(0.0,0.0,0.0); - return pi; - } - const Vector ddpnn_dv1(dp*dnn_dv1+dp_dv1*nn); - const Vector ddpnn_dv2(dp*dnn_dv2+dp_dv2*nn); + if(dpnn>=1.0-epsilon) { + d1=Vector(0.0,0.0,0.0); + d2=Vector(0.0,0.0,0.0); + return 0.0; + } + if(dpnn<=-1.0+epsilon) { + d1=Vector(0.0,0.0,0.0); + d2=Vector(0.0,0.0,0.0); + return pi; + } + const Vector ddpnn_dv1(dp*dnn_dv1+dp_dv1*nn); + const Vector ddpnn_dv2(dp*dnn_dv2+dp_dv2*nn); - const double x(-1.0/sqrt(1-dpnn*dpnn)); + const double x(-1.0/sqrt(1-dpnn*dpnn)); - d1=x*ddpnn_dv1; - d2=x*ddpnn_dv2; + d1=x*ddpnn_dv1; + d2=x*ddpnn_dv2; - return std::acos(dpnn); + return std::acos(dpnn); } } diff --git a/src/tools/Angle.h b/src/tools/Angle.h index 9a9f2b200..1d6a58e52 100644 --- a/src/tools/Angle.h +++ b/src/tools/Angle.h @@ -24,7 +24,7 @@ #include "Vector.h" -namespace PLMD{ +namespace PLMD { /// \ingroup TOOLBOX /// Class to compute angles. @@ -36,7 +36,7 @@ namespace PLMD{ /// I know it is a bit misleading. If we really do not need to store "options" /// inside the Angle class, we can remove it later and write compute as /// a static function. -class Angle{ +class Angle { // still empty, but may accomodate some options in the future public: /// Compute the angle between vectors v1 and v2 diff --git a/src/tools/AtomNumber.h b/src/tools/AtomNumber.h index b15018930..60eb9ca77 100644 --- a/src/tools/AtomNumber.h +++ b/src/tools/AtomNumber.h @@ -25,7 +25,7 @@ #include "Exception.h" #include <limits> -namespace PLMD{ +namespace PLMD { /** \ingroup TOOLBOX @@ -36,7 +36,7 @@ namespace PLMD{ no ambiguity about using the "from 0" (index) or "from 1" (serial) numbering (names as in VMD convention). */ -class AtomNumber{ +class AtomNumber { unsigned index_; /// Construct with a given index. /// This constructor is kept private to avoid implicit cast. @@ -71,27 +71,27 @@ public: }; inline -AtomNumber::AtomNumber(){ +AtomNumber::AtomNumber() { index_=0; } inline -AtomNumber::AtomNumber(unsigned i){ +AtomNumber::AtomNumber(unsigned i) { index_=i; } inline -unsigned AtomNumber::serial()const{ +unsigned AtomNumber::serial()const { return index_+1; } inline -unsigned AtomNumber::index()const{ +unsigned AtomNumber::index()const { return index_; } inline -AtomNumber & AtomNumber::setSerial(unsigned i){ +AtomNumber & AtomNumber::setSerial(unsigned i) { plumed_massert(i>0,"serial of an atom cannot be zero"); plumed_massert(i<std::numeric_limits<unsigned>::max()/2,"serial cannot be negative"); index_=i-1; @@ -99,50 +99,50 @@ AtomNumber & AtomNumber::setSerial(unsigned i){ } inline -AtomNumber & AtomNumber::setIndex(unsigned i){ +AtomNumber & AtomNumber::setIndex(unsigned i) { index_=i; return *this; } inline -AtomNumber AtomNumber::serial(unsigned i){ +AtomNumber AtomNumber::serial(unsigned i) { plumed_massert(i>0,"serial of an atom cannot be zero"); plumed_massert(i<std::numeric_limits<unsigned>::max()/2,"serial cannot be negative"); return AtomNumber(i-1); } inline -AtomNumber AtomNumber::index(unsigned i){ +AtomNumber AtomNumber::index(unsigned i) { return AtomNumber(i); } inline -bool operator<(const AtomNumber&a,const AtomNumber&b){ +bool operator<(const AtomNumber&a,const AtomNumber&b) { return a.index_<b.index_; } inline -bool operator>(const AtomNumber&a,const AtomNumber&b){ +bool operator>(const AtomNumber&a,const AtomNumber&b) { return a.index_>b.index_; } inline -bool operator<=(const AtomNumber&a,const AtomNumber&b){ +bool operator<=(const AtomNumber&a,const AtomNumber&b) { return a.index_<=b.index_; } inline -bool operator>=(const AtomNumber&a,const AtomNumber&b){ +bool operator>=(const AtomNumber&a,const AtomNumber&b) { return a.index_>=b.index_; } inline -bool operator==(const AtomNumber&a,const AtomNumber&b){ +bool operator==(const AtomNumber&a,const AtomNumber&b) { return a.index_==b.index_; } inline -bool operator!=(const AtomNumber&a,const AtomNumber&b){ +bool operator!=(const AtomNumber&a,const AtomNumber&b) { return a.index_!=b.index_; } diff --git a/src/tools/BiasRepresentation.cpp b/src/tools/BiasRepresentation.cpp index 89ae941a5..d37be2916 100644 --- a/src/tools/BiasRepresentation.cpp +++ b/src/tools/BiasRepresentation.cpp @@ -29,247 +29,247 @@ namespace PLMD { using namespace std; /// the constructor here -BiasRepresentation::BiasRepresentation(const vector<Value*> & tmpvalues, Communicator &cc ):hasgrid(false),rescaledToBias(false),mycomm(cc),BiasGrid_(NULL){ - lowI_=0.0; - uppI_=0.0; - doInt_=false; - ndim=tmpvalues.size(); - for(int i=0;i<ndim;i++){ - values.push_back(tmpvalues[i]); - names.push_back(values[i]->getName()); - } +BiasRepresentation::BiasRepresentation(const vector<Value*> & tmpvalues, Communicator &cc ):hasgrid(false),rescaledToBias(false),mycomm(cc),BiasGrid_(NULL) { + lowI_=0.0; + uppI_=0.0; + doInt_=false; + ndim=tmpvalues.size(); + for(int i=0; i<ndim; i++) { + values.push_back(tmpvalues[i]); + names.push_back(values[i]->getName()); + } +} +/// overload the constructor: add the sigma at constructor time +BiasRepresentation::BiasRepresentation(const vector<Value*> & tmpvalues, Communicator &cc, const vector<double> & sigma ):hasgrid(false), rescaledToBias(false), histosigma(sigma),mycomm(cc),BiasGrid_(NULL) { + lowI_=0.0; + uppI_=0.0; + doInt_=false; + ndim=tmpvalues.size(); + for(int i=0; i<ndim; i++) { + values.push_back(tmpvalues[i]); + names.push_back(values[i]->getName()); + } +} +/// overload the constructor: add the grid at constructor time +BiasRepresentation::BiasRepresentation(const vector<Value*> & tmpvalues, Communicator &cc, const vector<string> & gmin, const vector<string> & gmax, + const vector<unsigned> & nbin, bool doInt, double lowI, double uppI ):hasgrid(false), rescaledToBias(false), mycomm(cc), BiasGrid_(NULL) { + ndim=tmpvalues.size(); + for(int i=0; i<ndim; i++) { + values.push_back(tmpvalues[i]); + names.push_back(values[i]->getName()); + } + doInt_=doInt; + lowI_=lowI; + uppI_=uppI; + // initialize the grid + addGrid(gmin,gmax,nbin); } -/// overload the constructor: add the sigma at constructor time -BiasRepresentation::BiasRepresentation(const vector<Value*> & tmpvalues, Communicator &cc, const vector<double> & sigma ):hasgrid(false), rescaledToBias(false), histosigma(sigma),mycomm(cc),BiasGrid_(NULL){ - lowI_=0.0; - uppI_=0.0; - doInt_=false; - ndim=tmpvalues.size(); - for(int i=0;i<ndim;i++){ - values.push_back(tmpvalues[i]); - names.push_back(values[i]->getName()); - } -} -/// overload the constructor: add the grid at constructor time -BiasRepresentation::BiasRepresentation(const vector<Value*> & tmpvalues, Communicator &cc , const vector<string> & gmin, const vector<string> & gmax, - const vector<unsigned> & nbin, bool doInt, double lowI, double uppI ):hasgrid(false), rescaledToBias(false), mycomm(cc), BiasGrid_(NULL){ - ndim=tmpvalues.size(); - for(int i=0;i<ndim;i++){ - values.push_back(tmpvalues[i]); - names.push_back(values[i]->getName()); - } - doInt_=doInt; - lowI_=lowI; - uppI_=uppI; - // initialize the grid - addGrid(gmin,gmax,nbin); -} /// overload the constructor with some external sigmas: needed for histogram -BiasRepresentation::BiasRepresentation(const vector<Value*> & tmpvalues, Communicator &cc , const vector<string> & gmin, const vector<string> & gmax, const vector<unsigned> & nbin , const vector<double> & sigma):hasgrid(false), rescaledToBias(false),histosigma(sigma),mycomm(cc),BiasGrid_(NULL){ - lowI_=0.0; - uppI_=0.0; - doInt_=false; - ndim=tmpvalues.size(); - for(int i=0;i<ndim;i++){ - values.push_back(tmpvalues[i]); - names.push_back(values[i]->getName()); - } - // initialize the grid - addGrid(gmin,gmax,nbin); +BiasRepresentation::BiasRepresentation(const vector<Value*> & tmpvalues, Communicator &cc, const vector<string> & gmin, const vector<string> & gmax, const vector<unsigned> & nbin, const vector<double> & sigma):hasgrid(false), rescaledToBias(false),histosigma(sigma),mycomm(cc),BiasGrid_(NULL) { + lowI_=0.0; + uppI_=0.0; + doInt_=false; + ndim=tmpvalues.size(); + for(int i=0; i<ndim; i++) { + values.push_back(tmpvalues[i]); + names.push_back(values[i]->getName()); + } + // initialize the grid + addGrid(gmin,gmax,nbin); } -BiasRepresentation::~BiasRepresentation(){ +BiasRepresentation::~BiasRepresentation() { if(BiasGrid_) delete BiasGrid_; - for(unsigned i=0;i<hills.size();i++) delete hills[i]; + for(unsigned i=0; i<hills.size(); i++) delete hills[i]; } -void BiasRepresentation::addGrid( const vector<string> & gmin, const vector<string> & gmax, const vector<unsigned> & nbin ){ - plumed_massert(hills.size()==0,"you can set the grid before loading the hills"); - plumed_massert(hasgrid==false,"to build the grid you should not having the grid in this bias representation"); - string ss; ss="file.free"; - vector<Value*> vv;for(unsigned i=0;i<values.size();i++)vv.push_back(values[i]); - //cerr<<" initializing grid "<<endl; - BiasGrid_=new Grid(ss,vv,gmin,gmax,nbin,false,true); - hasgrid=true; +void BiasRepresentation::addGrid( const vector<string> & gmin, const vector<string> & gmax, const vector<unsigned> & nbin ) { + plumed_massert(hills.size()==0,"you can set the grid before loading the hills"); + plumed_massert(hasgrid==false,"to build the grid you should not having the grid in this bias representation"); + string ss; ss="file.free"; + vector<Value*> vv; for(unsigned i=0; i<values.size(); i++)vv.push_back(values[i]); + //cerr<<" initializing grid "<<endl; + BiasGrid_=new Grid(ss,vv,gmin,gmax,nbin,false,true); + hasgrid=true; } -bool BiasRepresentation::hasSigmaInInput(){ - if(histosigma.size()==0){return false;}else{return true;} +bool BiasRepresentation::hasSigmaInInput() { + if(histosigma.size()==0) {return false;} else {return true;} } -void BiasRepresentation::setRescaledToBias(bool rescaled){ - plumed_massert(hills.size()==0,"you can set the rescaling function only before loading hills"); - rescaledToBias=rescaled; +void BiasRepresentation::setRescaledToBias(bool rescaled) { + plumed_massert(hills.size()==0,"you can set the rescaling function only before loading hills"); + rescaledToBias=rescaled; } -const bool & BiasRepresentation::isRescaledToBias(){ - return rescaledToBias; +const bool & BiasRepresentation::isRescaledToBias() { + return rescaledToBias; } -unsigned BiasRepresentation::getNumberOfDimensions(){ - return values.size(); -} -vector<string> BiasRepresentation::getNames(){ - return names; -} -const string & BiasRepresentation::getName(unsigned i){ - return names[i]; -} +unsigned BiasRepresentation::getNumberOfDimensions() { + return values.size(); +} +vector<string> BiasRepresentation::getNames() { + return names; +} +const string & BiasRepresentation::getName(unsigned i) { + return names[i]; +} -const vector<Value*>& BiasRepresentation::getPtrToValues(){ - return values; -} -Value* BiasRepresentation::getPtrToValue(unsigned i){ - return values[i]; -} +const vector<Value*>& BiasRepresentation::getPtrToValues() { + return values; +} +Value* BiasRepresentation::getPtrToValue(unsigned i) { + return values[i]; +} -KernelFunctions* BiasRepresentation::readFromPoint(IFile *ifile){ - vector<double> cc( names.size() ); - for(unsigned i=0;i<names.size();++i){ - ifile->scanField(names[i],cc[i]); - } - double h=1.0; - return new KernelFunctions(cc,histosigma,"gaussian",false,h,false); +KernelFunctions* BiasRepresentation::readFromPoint(IFile *ifile) { + vector<double> cc( names.size() ); + for(unsigned i=0; i<names.size(); ++i) { + ifile->scanField(names[i],cc[i]); + } + double h=1.0; + return new KernelFunctions(cc,histosigma,"gaussian",false,h,false); } -void BiasRepresentation::pushKernel( IFile *ifile ){ - KernelFunctions *kk=NULL; - // here below the reading of the kernel is completely hidden - if(histosigma.size()==0){ - ifile->allowIgnoredFields(); - kk=KernelFunctions::read(ifile,names) ; - }else{ - // when doing histogram assume gaussian with a given diagonal sigma - // and neglect all the rest - kk=readFromPoint(ifile) ; - } - hills.push_back(kk); - // the bias factor is not something about the kernels but - // must be stored to keep the bias/free energy duality - string dummy; double dummyd; - if(ifile->FieldExist("biasf")){ - ifile->scanField("biasf",dummy); - Tools::convert(dummy,dummyd); - }else{dummyd=1.0;} - biasf.push_back(dummyd); - // the domain does not pertain to the kernel but to the values here defined - string mins,maxs,minv,maxv,mini,maxi;mins="min_";maxs="max_"; - for(int i=0 ; i<ndim; i++){ - if(values[i]->isPeriodic()){ - ifile->scanField(mins+names[i],minv); - ifile->scanField(maxs+names[i],maxv); - // verify that the domain is correct - values[i]->getDomain(mini,maxi); - plumed_massert(mini==minv,"the input periodicity in hills and in value definition does not match" ); - plumed_massert(maxi==maxv,"the input periodicity in hills and in value definition does not match" ); - } +void BiasRepresentation::pushKernel( IFile *ifile ) { + KernelFunctions *kk=NULL; + // here below the reading of the kernel is completely hidden + if(histosigma.size()==0) { + ifile->allowIgnoredFields(); + kk=KernelFunctions::read(ifile,names) ; + } else { + // when doing histogram assume gaussian with a given diagonal sigma + // and neglect all the rest + kk=readFromPoint(ifile) ; + } + hills.push_back(kk); + // the bias factor is not something about the kernels but + // must be stored to keep the bias/free energy duality + string dummy; double dummyd; + if(ifile->FieldExist("biasf")) { + ifile->scanField("biasf",dummy); + Tools::convert(dummy,dummyd); + } else {dummyd=1.0;} + biasf.push_back(dummyd); + // the domain does not pertain to the kernel but to the values here defined + string mins,maxs,minv,maxv,mini,maxi; mins="min_"; maxs="max_"; + for(int i=0 ; i<ndim; i++) { + if(values[i]->isPeriodic()) { + ifile->scanField(mins+names[i],minv); + ifile->scanField(maxs+names[i],maxv); + // verify that the domain is correct + values[i]->getDomain(mini,maxi); + plumed_massert(mini==minv,"the input periodicity in hills and in value definition does not match" ); + plumed_massert(maxi==maxv,"the input periodicity in hills and in value definition does not match" ); + } + } + // if grid is defined then it should be added on the grid + //cerr<<"now with "<<hills.size()<<endl; + if(hasgrid) { + vector<unsigned> nneighb; + if(doInt_&&(kk->getCenter()[0]+kk->getContinuousSupport()[0] > uppI_ || kk->getCenter()[0]-kk->getContinuousSupport()[0] < lowI_ )) { + nneighb=BiasGrid_->getNbin(); + } else nneighb=kk->getSupport(BiasGrid_->getDx()); + vector<Grid::index_t> neighbors=BiasGrid_->getNeighbors(kk->getCenter(),nneighb); + vector<double> der(ndim); + vector<double> xx(ndim); + if(mycomm.Get_size()==1) { + for(unsigned i=0; i<neighbors.size(); ++i) { + Grid::index_t ineigh=neighbors[i]; + for(int j=0; j<ndim; ++j) {der[j]=0.0;} + BiasGrid_->getPoint(ineigh,xx); + // assign xx to a new vector of values + for(int j=0; j<ndim; ++j) {values[j]->set(xx[j]);} + double bias; + if(doInt_) bias=kk->evaluate(values,der,true,doInt_,lowI_,uppI_); + else bias=kk->evaluate(values,der,true); + if(rescaledToBias) { + double f=(biasf.back()-1.)/(biasf.back()); + bias*=f; + for(int j=0; j<ndim; ++j) {der[j]*=f;} } - // if grid is defined then it should be added on the grid - //cerr<<"now with "<<hills.size()<<endl; - if(hasgrid){ - vector<unsigned> nneighb; - if(doInt_&&(kk->getCenter()[0]+kk->getContinuousSupport()[0] > uppI_ || kk->getCenter()[0]-kk->getContinuousSupport()[0] < lowI_ )) { - nneighb=BiasGrid_->getNbin(); - } else nneighb=kk->getSupport(BiasGrid_->getDx()); - vector<Grid::index_t> neighbors=BiasGrid_->getNeighbors(kk->getCenter(),nneighb); - vector<double> der(ndim); - vector<double> xx(ndim); - if(mycomm.Get_size()==1){ - for(unsigned i=0;i<neighbors.size();++i){ - Grid::index_t ineigh=neighbors[i]; - for(int j=0;j<ndim;++j){der[j]=0.0;} - BiasGrid_->getPoint(ineigh,xx); - // assign xx to a new vector of values - for(int j=0;j<ndim;++j){values[j]->set(xx[j]);} - double bias; - if(doInt_) bias=kk->evaluate(values,der,true,doInt_,lowI_,uppI_); - else bias=kk->evaluate(values,der,true); - if(rescaledToBias){ - double f=(biasf.back()-1.)/(biasf.back()); - bias*=f; - for(int j=0;j<ndim;++j){der[j]*=f;} - } - BiasGrid_->addValueAndDerivatives(ineigh,bias,der); - } - } else { - unsigned stride=mycomm.Get_size(); - unsigned rank=mycomm.Get_rank(); - vector<double> allder(ndim*neighbors.size(),0.0); - vector<double> allbias(neighbors.size(),0.0); - vector<double> tmpder(ndim); - for(unsigned i=rank;i<neighbors.size();i+=stride){ - Grid::index_t ineigh=neighbors[i]; - BiasGrid_->getPoint(ineigh,xx); - for(int j=0;j<ndim;++j){values[j]->set(xx[j]);} - if(doInt_) allbias[i]=kk->evaluate(values,der,true,doInt_,lowI_,uppI_); - else allbias[i]=kk->evaluate(values,der,true); - if(rescaledToBias){ - double f=(biasf.back()-1.)/(biasf.back()); - allbias[i]*=f; - for(int j=0;j<ndim;++j){tmpder[j]*=f;} - } - // this solution with the temporary vector is rather bad, probably better to take - // a pointer of double as it was in old gaussian - for(int j=0;j<ndim;++j){ allder[ndim*i+j]=tmpder[j]; tmpder[j]=0.;} - } - mycomm.Sum(allbias); - mycomm.Sum(allder); - for(unsigned i=0;i<neighbors.size();++i){ - Grid::index_t ineigh=neighbors[i]; - for(int j=0;j<ndim;++j){der[j]=allder[ndim*i+j];} - BiasGrid_->addValueAndDerivatives(ineigh,allbias[i],der); - } - } + BiasGrid_->addValueAndDerivatives(ineigh,bias,der); + } + } else { + unsigned stride=mycomm.Get_size(); + unsigned rank=mycomm.Get_rank(); + vector<double> allder(ndim*neighbors.size(),0.0); + vector<double> allbias(neighbors.size(),0.0); + vector<double> tmpder(ndim); + for(unsigned i=rank; i<neighbors.size(); i+=stride) { + Grid::index_t ineigh=neighbors[i]; + BiasGrid_->getPoint(ineigh,xx); + for(int j=0; j<ndim; ++j) {values[j]->set(xx[j]);} + if(doInt_) allbias[i]=kk->evaluate(values,der,true,doInt_,lowI_,uppI_); + else allbias[i]=kk->evaluate(values,der,true); + if(rescaledToBias) { + double f=(biasf.back()-1.)/(biasf.back()); + allbias[i]*=f; + for(int j=0; j<ndim; ++j) {tmpder[j]*=f;} } + // this solution with the temporary vector is rather bad, probably better to take + // a pointer of double as it was in old gaussian + for(int j=0; j<ndim; ++j) { allder[ndim*i+j]=tmpder[j]; tmpder[j]=0.;} + } + mycomm.Sum(allbias); + mycomm.Sum(allder); + for(unsigned i=0; i<neighbors.size(); ++i) { + Grid::index_t ineigh=neighbors[i]; + for(int j=0; j<ndim; ++j) {der[j]=allder[ndim*i+j];} + BiasGrid_->addValueAndDerivatives(ineigh,allbias[i],der); + } + } + } } -int BiasRepresentation::getNumberOfKernels(){ - return hills.size(); +int BiasRepresentation::getNumberOfKernels() { + return hills.size(); } -Grid* BiasRepresentation::getGridPtr(){ - plumed_massert(hasgrid,"if you want the grid pointer then you should have defined a grid before"); - return BiasGrid_; +Grid* BiasRepresentation::getGridPtr() { + plumed_massert(hasgrid,"if you want the grid pointer then you should have defined a grid before"); + return BiasGrid_; } -void BiasRepresentation::getMinMaxBin(vector<double> &vmin, vector<double> &vmax, vector<unsigned> &vbin){ - vector<double> ss,cc,binsize; - vmin.clear();vmin.resize(ndim,10.e20); - vmax.clear();vmax.resize(ndim,-10.e20); - vbin.clear();vbin.resize(ndim); - binsize.clear();binsize.resize(ndim,10.e20); - int ndiv=10; // adjustable parameter: division per support - for(unsigned i=0;i<hills.size();i++){ - if(histosigma.size()!=0){ - ss=histosigma; - }else{ - ss=hills[i]->getContinuousSupport(); - } - cc=hills[i]->getCenter(); - for(int j=0;j<ndim;j++){ - double dmin=cc[j]-ss[j]; - double dmax=cc[j]+ss[j]; - double ddiv=ss[j]/double(ndiv); - if(dmin<vmin[j])vmin[j]=dmin; - if(dmax>vmax[j])vmax[j]=dmax; - if(ddiv<binsize[j])binsize[j]=ddiv; - } - } - for(int j=0;j<ndim;j++){ - // reset to periodicity - if(values[j]->isPeriodic()){ - double minv,maxv; - values[j]->getDomain(minv,maxv); - if(minv>vmin[j])vmin[j]=minv; - if(maxv<vmax[j])vmax[j]=maxv; - } - vbin[j]=static_cast<unsigned>(ceil((vmax[j]-vmin[j])/binsize[j]) ); - } +void BiasRepresentation::getMinMaxBin(vector<double> &vmin, vector<double> &vmax, vector<unsigned> &vbin) { + vector<double> ss,cc,binsize; + vmin.clear(); vmin.resize(ndim,10.e20); + vmax.clear(); vmax.resize(ndim,-10.e20); + vbin.clear(); vbin.resize(ndim); + binsize.clear(); binsize.resize(ndim,10.e20); + int ndiv=10; // adjustable parameter: division per support + for(unsigned i=0; i<hills.size(); i++) { + if(histosigma.size()!=0) { + ss=histosigma; + } else { + ss=hills[i]->getContinuousSupport(); + } + cc=hills[i]->getCenter(); + for(int j=0; j<ndim; j++) { + double dmin=cc[j]-ss[j]; + double dmax=cc[j]+ss[j]; + double ddiv=ss[j]/double(ndiv); + if(dmin<vmin[j])vmin[j]=dmin; + if(dmax>vmax[j])vmax[j]=dmax; + if(ddiv<binsize[j])binsize[j]=ddiv; + } + } + for(int j=0; j<ndim; j++) { + // reset to periodicity + if(values[j]->isPeriodic()) { + double minv,maxv; + values[j]->getDomain(minv,maxv); + if(minv>vmin[j])vmin[j]=minv; + if(maxv<vmax[j])vmax[j]=maxv; + } + vbin[j]=static_cast<unsigned>(ceil((vmax[j]-vmin[j])/binsize[j]) ); + } } -void BiasRepresentation::clear(){ - // clear the hills - for(const auto & it : hills) - { - delete it; - } - hills.clear(); - // clear the grid - if(hasgrid){ - BiasGrid_->clear(); - } +void BiasRepresentation::clear() { + // clear the hills + for(const auto & it : hills) + { + delete it; + } + hills.clear(); + // clear the grid + if(hasgrid) { + BiasGrid_->clear(); + } } diff --git a/src/tools/BiasRepresentation.h b/src/tools/BiasRepresentation.h index a66bf3778..9533e53c4 100644 --- a/src/tools/BiasRepresentation.h +++ b/src/tools/BiasRepresentation.h @@ -27,75 +27,75 @@ #include "File.h" #include "Grid.h" -namespace PLMD{ +namespace PLMD { -//+PLUMEDOC INTERNAL biasrepresentation +//+PLUMEDOC INTERNAL biasrepresentation /* */ //+ENDPLUMEDOC -/// this class implements a general purpose class that aims to -/// provide a Grid/list -/// transparently add gaussians to a bias +/// this class implements a general purpose class that aims to +/// provide a Grid/list +/// transparently add gaussians to a bias class BiasRepresentation { - public: - /// create a bias representation from a list of pointer to values - BiasRepresentation(const std::vector<Value*> & tmpvalues, Communicator &cc ); - /// create a bias using explicit sigma in input (needed for histogram building) - BiasRepresentation(const std::vector<Value*> & tmpvalues, Communicator &cc , const std::vector<double> & sigma); - /// create a bias containing a grid representation - BiasRepresentation(const std::vector<Value*> & tmpvalues, Communicator &cc , const std::vector<std::string> & gmin, const std::vector<std::string> & gmax, - const std::vector<unsigned> & nbin, bool doInt, double lowI_, double uppI_); - /// create a histogram with grid representation and sigmas in input - BiasRepresentation(const std::vector<Value*> & tmpvalues, Communicator &cc , const std::vector<std::string> & gmin, const std::vector<std::string> & gmax, const std::vector<unsigned> & nbin , const std::vector<double> & sigma); - /// destructor - ~BiasRepresentation(); - /// retrieve the number of dimension of the representation - unsigned getNumberOfDimensions(); - /// add the grid to the representation - void addGrid(const std::vector<std::string> & gmin, const std::vector<std::string> & gmax, const std::vector<unsigned> & nbin ); - /// push a kernel on the representation (includes widths and height) - void pushKernel( IFile * ff); - /// set the flag that rescales the free energy to the bias - void setRescaledToBias(bool rescaled); - /// check if the representation is rescaled to the bias - const bool & isRescaledToBias(); - /// check if the sigma values are already provided (in case of a histogram representation with input sigmas) - bool hasSigmaInInput(); - /// get the names of the variables - std::vector<std::string> getNames(); - /// get the pointer to the values - const std::vector<Value*> & getPtrToValues(); - /// get the number of kernels contained in the representation - int getNumberOfKernels(); - /// get the name of the i-th value - const std::string & getName(unsigned i); - /// get a pointer to a specific value - Value* getPtrToValue(unsigned i); - /// get the pointer to the grid - Grid* getGridPtr(); - /// get a new histogram point from a file - KernelFunctions* readFromPoint(IFile *ifile); - /// get an automatic min/max from the set so to know how to configure the grid - void getMinMaxBin(std::vector<double> &vmin, std::vector<double> &vmax, std::vector<unsigned> &vbin); - /// clear the representation (grid included) - void clear(); - private: - int ndim; - bool hasgrid; - bool rescaledToBias; - bool doInt_; - double lowI_; - double uppI_; - std::vector<Value*> values; - std::vector<std::string> names; - std::vector<KernelFunctions*> hills; - std::vector<double> biasf; - std::vector<double> histosigma; - Communicator& mycomm; - Grid* BiasGrid_; +public: + /// create a bias representation from a list of pointer to values + BiasRepresentation(const std::vector<Value*> & tmpvalues, Communicator &cc ); + /// create a bias using explicit sigma in input (needed for histogram building) + BiasRepresentation(const std::vector<Value*> & tmpvalues, Communicator &cc, const std::vector<double> & sigma); + /// create a bias containing a grid representation + BiasRepresentation(const std::vector<Value*> & tmpvalues, Communicator &cc, const std::vector<std::string> & gmin, const std::vector<std::string> & gmax, + const std::vector<unsigned> & nbin, bool doInt, double lowI_, double uppI_); + /// create a histogram with grid representation and sigmas in input + BiasRepresentation(const std::vector<Value*> & tmpvalues, Communicator &cc, const std::vector<std::string> & gmin, const std::vector<std::string> & gmax, const std::vector<unsigned> & nbin, const std::vector<double> & sigma); + /// destructor + ~BiasRepresentation(); + /// retrieve the number of dimension of the representation + unsigned getNumberOfDimensions(); + /// add the grid to the representation + void addGrid(const std::vector<std::string> & gmin, const std::vector<std::string> & gmax, const std::vector<unsigned> & nbin ); + /// push a kernel on the representation (includes widths and height) + void pushKernel( IFile * ff); + /// set the flag that rescales the free energy to the bias + void setRescaledToBias(bool rescaled); + /// check if the representation is rescaled to the bias + const bool & isRescaledToBias(); + /// check if the sigma values are already provided (in case of a histogram representation with input sigmas) + bool hasSigmaInInput(); + /// get the names of the variables + std::vector<std::string> getNames(); + /// get the pointer to the values + const std::vector<Value*> & getPtrToValues(); + /// get the number of kernels contained in the representation + int getNumberOfKernels(); + /// get the name of the i-th value + const std::string & getName(unsigned i); + /// get a pointer to a specific value + Value* getPtrToValue(unsigned i); + /// get the pointer to the grid + Grid* getGridPtr(); + /// get a new histogram point from a file + KernelFunctions* readFromPoint(IFile *ifile); + /// get an automatic min/max from the set so to know how to configure the grid + void getMinMaxBin(std::vector<double> &vmin, std::vector<double> &vmax, std::vector<unsigned> &vbin); + /// clear the representation (grid included) + void clear(); +private: + int ndim; + bool hasgrid; + bool rescaledToBias; + bool doInt_; + double lowI_; + double uppI_; + std::vector<Value*> values; + std::vector<std::string> names; + std::vector<KernelFunctions*> hills; + std::vector<double> biasf; + std::vector<double> histosigma; + Communicator& mycomm; + Grid* BiasGrid_; }; } diff --git a/src/tools/Brent1DRootSearch.h b/src/tools/Brent1DRootSearch.h index 39ccdfcc4..138760737 100644 --- a/src/tools/Brent1DRootSearch.h +++ b/src/tools/Brent1DRootSearch.h @@ -27,7 +27,7 @@ #include <vector> #include <string> -namespace PLMD{ +namespace PLMD { /// A class for doing parabolic interpolation and minimisation of /// 1D functions using Brent's method. @@ -40,7 +40,7 @@ private: double tol; /// Maximum number of interactions in line minimiser const unsigned ITMAX; -/// A small number that protects against trying to achieve fractional +/// A small number that protects against trying to achieve fractional /// accuracy for a minimum that happens to be exactly zero const double EPS; /// The factor by which to expand the range when bracketing @@ -53,67 +53,67 @@ private: FCLASS myclass_func; public: explicit Brent1DRootSearch( const FCLASS& pf, const double& t=3.0E-8 ); -/// Bracket the minium +/// Bracket the minium void bracket( const double& ax, const double& xx, eng_pointer eng ); /// Find the minimum between two brackets - double search( eng_pointer eng ); + double search( eng_pointer eng ); }; template <class FCLASS> Brent1DRootSearch<FCLASS>::Brent1DRootSearch( const FCLASS& pf, const double& t ): -bracketed(false), -tol(t), -ITMAX(100), -EPS(3.0E-8), -EXPAND(1.6), -ax(0), bx(0), -fa(0), fb(0), -myclass_func(pf) + bracketed(false), + tol(t), + ITMAX(100), + EPS(3.0E-8), + EXPAND(1.6), + ax(0), bx(0), + fa(0), fb(0), + myclass_func(pf) { } template <class FCLASS> -void Brent1DRootSearch<FCLASS>::bracket( const double& a, const double& b, eng_pointer eng ){ - plumed_assert( a!=b ); ax=a; bx=b; fa=(myclass_func.*eng)(a); fb=(myclass_func.*eng)(b); - if ((fa > 0.0 && fb > 0.0) || (fa < 0.0 && fb < 0.0)) plumed_merror("input points do not bracket root"); - bracketed=true; +void Brent1DRootSearch<FCLASS>::bracket( const double& a, const double& b, eng_pointer eng ) { + plumed_assert( a!=b ); ax=a; bx=b; fa=(myclass_func.*eng)(a); fb=(myclass_func.*eng)(b); + if ((fa > 0.0 && fb > 0.0) || (fa < 0.0 && fb < 0.0)) plumed_merror("input points do not bracket root"); + bracketed=true; } template <class FCLASS> -double Brent1DRootSearch<FCLASS>::search( eng_pointer eng ){ - plumed_dbg_assert( bracketed ); +double Brent1DRootSearch<FCLASS>::search( eng_pointer eng ) { + plumed_dbg_assert( bracketed ); - double cx=bx, d, e, min1, min2, fc=fb, p, q, r, s, tol1, xm; - for(unsigned iter=0;iter<ITMAX;iter++) { - if ( (fb>0.0 && fc>0.0) || (fb<0.0 && fc<0.0) ){ cx=ax; fc=fa; e=d=bx-ax; } - if( fabs(fc) < fabs(fb) ){ ax=bx; bx=cx; cx=ax; fa=fb; fb=fc; fc=fa; } - tol1=2*EPS*fabs(bx)+0.5*tol; xm=0.5*(cx-bx); - if( fabs(xm) <= tol1 || fb == 0.0 ) return bx; - if( fabs(e) >= tol1 && fabs(fa) > fabs(fb) ){ - s=fb/fa; - if( ax==cx ){ - p=2.0*xm*s; q=1.0-s; - } else { - q=fa/fc; r=fb/fc; p=s*(2.0*xm*q*(q-r)-(bx-ax)*(r-1.0)); q=(q-1.0)*(r-1.0)*(s-1.0); - } - if (p > 0.0) q = -q; - p=fabs(p); min1=3.0*xm*q-fabs(tol1*q); min2=fabs(e*q); - if (2.0*p < (min1 < min2 ? min1 : min2)) { - e=d; d=p/q; - } else { - d=xm; e=d; - } + double cx=bx, d, e, min1, min2, fc=fb, p, q, r, s, tol1, xm; + for(unsigned iter=0; iter<ITMAX; iter++) { + if ( (fb>0.0 && fc>0.0) || (fb<0.0 && fc<0.0) ) { cx=ax; fc=fa; e=d=bx-ax; } + if( fabs(fc) < fabs(fb) ) { ax=bx; bx=cx; cx=ax; fa=fb; fb=fc; fc=fa; } + tol1=2*EPS*fabs(bx)+0.5*tol; xm=0.5*(cx-bx); + if( fabs(xm) <= tol1 || fb == 0.0 ) return bx; + if( fabs(e) >= tol1 && fabs(fa) > fabs(fb) ) { + s=fb/fa; + if( ax==cx ) { + p=2.0*xm*s; q=1.0-s; } else { - d=xm; e=d; + q=fa/fc; r=fb/fc; p=s*(2.0*xm*q*(q-r)-(bx-ax)*(r-1.0)); q=(q-1.0)*(r-1.0)*(s-1.0); } - ax=bx; fa=fb; - if( fabs(d) > tol1 ) bx+=d; - else if(xm<0 ) bx -= fabs(tol1); // SIGN(tol1,xm); - else bx += tol1; - fb = (myclass_func.*eng)(bx); - } + if (p > 0.0) q = -q; + p=fabs(p); min1=3.0*xm*q-fabs(tol1*q); min2=fabs(e*q); + if (2.0*p < (min1 < min2 ? min1 : min2)) { + e=d; d=p/q; + } else { + d=xm; e=d; + } + } else { + d=xm; e=d; + } + ax=bx; fa=fb; + if( fabs(d) > tol1 ) bx+=d; + else if(xm<0 ) bx -= fabs(tol1); // SIGN(tol1,xm); + else bx += tol1; + fb = (myclass_func.*eng)(bx); + } - plumed_merror("Too many interactions in zbrent"); + plumed_merror("Too many interactions in zbrent"); } } diff --git a/src/tools/Citations.cpp b/src/tools/Citations.cpp index 0c320d4e9..508255c2c 100644 --- a/src/tools/Citations.cpp +++ b/src/tools/Citations.cpp @@ -25,11 +25,11 @@ #include <iostream> using namespace std; -namespace PLMD{ +namespace PLMD { -std::string Citations::cite(const std::string & item){ +std::string Citations::cite(const std::string & item) { unsigned i; - for(i=0;i<items.size();++i) if(items[i]==item) break; + for(i=0; i<items.size(); ++i) if(items[i]==item) break; if(i==items.size()) items.push_back(item); plumed_assert(i<items.size()); string ret; @@ -38,17 +38,17 @@ std::string Citations::cite(const std::string & item){ return ret; } -std::ostream & operator<<(std::ostream &log,const Citations&cit){ - for(unsigned i=0;i<cit.items.size();++i) +std::ostream & operator<<(std::ostream &log,const Citations&cit) { + for(unsigned i=0; i<cit.items.size(); ++i) log<<" ["<<i+1<<"] "<<cit.items[i]<<"\n"; return log; } -void Citations::clear(){ +void Citations::clear() { items.clear(); } -bool Citations::empty()const{ +bool Citations::empty()const { return items.empty(); } diff --git a/src/tools/Citations.h b/src/tools/Citations.h index 9073679ce..7d7ba10be 100644 --- a/src/tools/Citations.h +++ b/src/tools/Citations.h @@ -26,7 +26,7 @@ #include <string> #include <iosfwd> -namespace PLMD{ +namespace PLMD { /** \ingroup TOOLBOX @@ -51,7 +51,7 @@ int main(int argc,char**argv){ \endverbatim */ -class Citations{ +class Citations { std::vector<std::string> items; public: /// Add a citation. diff --git a/src/tools/Communicator.cpp b/src/tools/Communicator.cpp index e53b1db4d..ac10f3931 100644 --- a/src/tools/Communicator.cpp +++ b/src/tools/Communicator.cpp @@ -25,11 +25,11 @@ using namespace std; -namespace PLMD{ +namespace PLMD { Communicator::Communicator() #ifdef __PLUMED_HAS_MPI -: communicator(MPI_COMM_SELF) + : communicator(MPI_COMM_SELF) #endif { } @@ -38,7 +38,7 @@ Communicator::Communicator() // Member variable 'Communicator::communicator' is not initialized in the constructor // this is a false positive so I suppress it // cppcheck-suppress uninitMemberVar -Communicator::Communicator(const Communicator&pc){ +Communicator::Communicator(const Communicator&pc) { Set_comm(pc.communicator); } @@ -48,14 +48,14 @@ Communicator::Status Communicator::StatusIgnore; // Member variable 'Communicator::communicator' is not assigned a value in 'Communicator::operator=' // this is a false positive so I suppress it // cppcheck-suppress operatorEqVarError -Communicator& Communicator::operator=(const Communicator&pc){ - if (this != &pc){ - Set_comm(pc.communicator); +Communicator& Communicator::operator=(const Communicator&pc) { + if (this != &pc) { + Set_comm(pc.communicator); } return *this; } -int Communicator::Get_rank()const{ +int Communicator::Get_rank()const { int r=0; #ifdef __PLUMED_HAS_MPI if(initialized()) MPI_Comm_rank(communicator,&r); @@ -63,7 +63,7 @@ int Communicator::Get_rank()const{ return r; } -Communicator& Communicator::Get_world(){ +Communicator& Communicator::Get_world() { static Communicator c; #ifdef __PLUMED_HAS_MPI if(initialized()) c.communicator=MPI_COMM_WORLD; @@ -72,7 +72,7 @@ Communicator& Communicator::Get_world(){ } -int Communicator::Get_size()const{ +int Communicator::Get_size()const { int s=1; #ifdef __PLUMED_HAS_MPI if(initialized()) MPI_Comm_size(communicator,&s); @@ -80,9 +80,9 @@ int Communicator::Get_size()const{ return s; } -void Communicator::Set_comm(MPI_Comm c){ +void Communicator::Set_comm(MPI_Comm c) { #ifdef __PLUMED_HAS_MPI - if(initialized()){ + if(initialized()) { if(communicator!=MPI_COMM_SELF && communicator!=MPI_COMM_WORLD) MPI_Comm_free(&communicator); if(c!=MPI_COMM_SELF) MPI_Comm_dup(c,&communicator); } @@ -91,26 +91,26 @@ void Communicator::Set_comm(MPI_Comm c){ #endif } -Communicator::~Communicator(){ +Communicator::~Communicator() { #ifdef __PLUMED_HAS_MPI if(initialized() && communicator!=MPI_COMM_SELF && communicator!=MPI_COMM_WORLD) MPI_Comm_free(&communicator); #endif } -void Communicator::Set_comm(void*val){ +void Communicator::Set_comm(void*val) { #ifdef __PLUMED_HAS_MPI - plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized"); - if(val) Set_comm(*(MPI_Comm*)val); + plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized"); + if(val) Set_comm(*(MPI_Comm*)val); #else - (void) val; - plumed_merror("you are trying to use an MPI function, but PLUMED has been compiled without MPI support"); + (void) val; + plumed_merror("you are trying to use an MPI function, but PLUMED has been compiled without MPI support"); #endif } -void Communicator::Set_fcomm(void*val){ +void Communicator::Set_fcomm(void*val) { #ifdef __PLUMED_HAS_MPI - plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized"); - if(val){ + plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized"); + if(val) { MPI_Comm comm=MPI_Comm_f2c(*(MPI_Fint*)val); Set_comm(comm); } @@ -120,9 +120,9 @@ void Communicator::Set_fcomm(void*val){ #endif } -void Communicator::Abort(int errorcode){ +void Communicator::Abort(int errorcode) { #ifdef __PLUMED_HAS_MPI - if(initialized()){ + if(initialized()) { MPI_Abort(communicator,errorcode); } std::exit(errorcode); @@ -133,7 +133,7 @@ void Communicator::Abort(int errorcode){ // data should be passed by value to allow conversions // cppcheck-suppress passedByValue -void Communicator::Bcast(Data data,int root){ +void Communicator::Bcast(Data data,int root) { #if defined(__PLUMED_HAS_MPI) if(initialized()) MPI_Bcast(data.pointer,data.size,data.type,root,communicator); #else @@ -144,7 +144,7 @@ void Communicator::Bcast(Data data,int root){ // data should be passed by value to allow conversions // cppcheck-suppress passedByValue -void Communicator::Sum(Data data){ +void Communicator::Sum(Data data) { #if defined(__PLUMED_HAS_MPI) if(initialized()) MPI_Allreduce(MPI_IN_PLACE,data.pointer,data.size,data.type,MPI_SUM,communicator); #else @@ -154,7 +154,7 @@ void Communicator::Sum(Data data){ // data should be passed by value to allow conversions // cppcheck-suppress passedByValue -Communicator::Request Communicator::Isend(ConstData data,int source,int tag){ +Communicator::Request Communicator::Isend(ConstData data,int source,int tag) { Request req; #ifdef __PLUMED_HAS_MPI plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized"); @@ -171,7 +171,7 @@ Communicator::Request Communicator::Isend(ConstData data,int source,int tag){ // data should be passed by value to allow conversions // cppcheck-suppress passedByValue -void Communicator::Allgatherv(ConstData in,Data out,const int*recvcounts,const int*displs){ +void Communicator::Allgatherv(ConstData in,Data out,const int*recvcounts,const int*displs) { #if defined(__PLUMED_HAS_MPI) plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized"); void*s=const_cast<void*>((const void*)in.pointer); @@ -191,7 +191,7 @@ void Communicator::Allgatherv(ConstData in,Data out,const int*recvcounts,const i // data should be passed by value to allow conversions // cppcheck-suppress passedByValue -void Communicator::Allgather(ConstData in,Data out){ +void Communicator::Allgather(ConstData in,Data out) { #if defined(__PLUMED_HAS_MPI) plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized"); void*s=const_cast<void*>((const void*)in.pointer); @@ -207,7 +207,7 @@ void Communicator::Allgather(ConstData in,Data out){ // data should be passed by value to allow conversions // cppcheck-suppress passedByValue -void Communicator::Recv(Data data,int source,int tag,Status&status){ +void Communicator::Recv(Data data,int source,int tag,Status&status) { #ifdef __PLUMED_HAS_MPI plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized"); if(&status==&StatusIgnore) MPI_Recv(data.pointer,data.size,data.type,source,tag,communicator,MPI_STATUS_IGNORE); @@ -225,17 +225,17 @@ void Communicator::Recv(Data data,int source,int tag,Status&status){ -void Communicator::Barrier()const{ +void Communicator::Barrier()const { #ifdef __PLUMED_HAS_MPI if(initialized()) MPI_Barrier(communicator); #endif } -MPI_Comm & Communicator::Get_comm(){ - return communicator; +MPI_Comm & Communicator::Get_comm() { + return communicator; } -bool Communicator::initialized(){ +bool Communicator::initialized() { int flag=false; #if defined(__PLUMED_HAS_MPI) MPI_Initialized(&flag); @@ -244,9 +244,9 @@ bool Communicator::initialized(){ else return false; } -void Communicator::Request::wait(Status&s){ +void Communicator::Request::wait(Status&s) { #ifdef __PLUMED_HAS_MPI - plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized"); + plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized"); if(&s==&StatusIgnore) MPI_Wait(&r,MPI_STATUS_IGNORE); else MPI_Wait(&r,&s.s); #else @@ -256,23 +256,23 @@ void Communicator::Request::wait(Status&s){ } #ifdef __PLUMED_HAS_MPI -template<> MPI_Datatype Communicator::getMPIType<float>(){ return MPI_FLOAT;} -template<> MPI_Datatype Communicator::getMPIType<double>(){ return MPI_DOUBLE;} +template<> MPI_Datatype Communicator::getMPIType<float>() { return MPI_FLOAT;} +template<> MPI_Datatype Communicator::getMPIType<double>() { return MPI_DOUBLE;} template<> MPI_Datatype Communicator::getMPIType<int>() { return MPI_INT;} template<> MPI_Datatype Communicator::getMPIType<char>() { return MPI_CHAR;} template<> MPI_Datatype Communicator::getMPIType<unsigned>() { return MPI_UNSIGNED;} template<> MPI_Datatype Communicator::getMPIType<long unsigned>() { return MPI_UNSIGNED_LONG;} #else -template<> MPI_Datatype Communicator::getMPIType<float>(){ return MPI_Datatype();} -template<> MPI_Datatype Communicator::getMPIType<double>(){ return MPI_Datatype();} -template<> MPI_Datatype Communicator::getMPIType<int>(){ return MPI_Datatype();} -template<> MPI_Datatype Communicator::getMPIType<char>(){ return MPI_Datatype();} -template<> MPI_Datatype Communicator::getMPIType<unsigned>(){ return MPI_Datatype();} -template<> MPI_Datatype Communicator::getMPIType<long unsigned>(){ return MPI_Datatype();} +template<> MPI_Datatype Communicator::getMPIType<float>() { return MPI_Datatype();} +template<> MPI_Datatype Communicator::getMPIType<double>() { return MPI_Datatype();} +template<> MPI_Datatype Communicator::getMPIType<int>() { return MPI_Datatype();} +template<> MPI_Datatype Communicator::getMPIType<char>() { return MPI_Datatype();} +template<> MPI_Datatype Communicator::getMPIType<unsigned>() { return MPI_Datatype();} +template<> MPI_Datatype Communicator::getMPIType<long unsigned>() { return MPI_Datatype();} #endif -void Communicator::Split(int color,int key,Communicator&pc)const{ +void Communicator::Split(int color,int key,Communicator&pc)const { #ifdef __PLUMED_HAS_MPI MPI_Comm_split(communicator,color,key,&pc.communicator); #else @@ -283,7 +283,7 @@ void Communicator::Split(int color,int key,Communicator&pc)const{ #endif } -int Communicator::Status::Get_count(MPI_Datatype type)const{ +int Communicator::Status::Get_count(MPI_Datatype type)const { int i; #ifdef __PLUMED_HAS_MPI plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized"); diff --git a/src/tools/Communicator.h b/src/tools/Communicator.h index d7be6e7cf..86ef8314d 100644 --- a/src/tools/Communicator.h +++ b/src/tools/Communicator.h @@ -32,23 +32,23 @@ #include "Tensor.h" #include "Matrix.h" -namespace PLMD{ +namespace PLMD { #ifndef __PLUMED_HAS_MPI /// Surrogate of MPI_Comm when MPI library is not available - class MPI_Comm {}; +class MPI_Comm {}; /// Surrogate of MPI_Datatype when MPI library is not available - class MPI_Datatype {}; +class MPI_Datatype {}; /// Surrogate of MPI_Status when MPI library is not available - class MPI_Status {}; +class MPI_Status {}; /// Surrogate of MPI_Request when MPI library is not available - class MPI_Request {}; +class MPI_Request {}; #endif /// \ingroup TOOLBOX /// Class containing wrappers to MPI. /// All the MPI related stuff is relegated here. -class Communicator{ +class Communicator { /// Communicator MPI_Comm communicator; /// Function returning the MPI type. @@ -62,7 +62,7 @@ class Communicator{ /// is grouped into a single object. It can be built starting from /// different kinds of data. To implement compatibility of MPI wrappers /// with e.g. vectors, add constructors here. - struct Data{ + struct Data { void*pointer; int size; MPI_Datatype type; @@ -71,32 +71,32 @@ class Communicator{ /// Init from reference template <typename T> explicit Data(T&p): pointer(&p), size(1), type(getMPIType<T>()) {} /// Init from pointer to VectorGeneric - template <unsigned n> explicit Data(VectorGeneric<n> *p,int s): pointer(p), size(n*s), type(getMPIType<double>()) {} + template <unsigned n> explicit Data(VectorGeneric<n> *p,int s): pointer(p), size(n*s), type(getMPIType<double>()) {} /// Init from reference to VectorGeneric - template <unsigned n> explicit Data(VectorGeneric<n> &p): pointer(&p), size(n), type(getMPIType<double>()) {} + template <unsigned n> explicit Data(VectorGeneric<n> &p): pointer(&p), size(n), type(getMPIType<double>()) {} /// Init from pointer to TensorGeneric - template <unsigned n,unsigned m> explicit Data(TensorGeneric<n,m> *p,int s): pointer(p), size(n*m*s), type(getMPIType<double>()) {} + template <unsigned n,unsigned m> explicit Data(TensorGeneric<n,m> *p,int s): pointer(p), size(n*m*s), type(getMPIType<double>()) {} /// Init from reference to TensorGeneric - template <unsigned n,unsigned m> explicit Data(TensorGeneric<n,m> &p): pointer(&p), size(n*m), type(getMPIType<double>()) {} + template <unsigned n,unsigned m> explicit Data(TensorGeneric<n,m> &p): pointer(&p), size(n*m), type(getMPIType<double>()) {} /// Init from reference to std::vector - template <typename T> explicit Data(std::vector<T>&v){ - if(v.size()>0){ Data d(&v[0],v.size()); pointer=d.pointer; size=d.size; type=d.type; } + template <typename T> explicit Data(std::vector<T>&v) { + if(v.size()>0) { Data d(&v[0],v.size()); pointer=d.pointer; size=d.size; type=d.type; } else { pointer=NULL; size=0; } } /// Init from reference to PLMD::Matrix - template <typename T> explicit Data(Matrix<T>&m ){ - if(m.nrows()*m.ncols()>0){ Data d(&m(0,0),m.nrows()*m.ncols()); pointer=d.pointer; size=d.size; type=d.type; } - else{ pointer=NULL; size=0; } + template <typename T> explicit Data(Matrix<T>&m ) { + if(m.nrows()*m.ncols()>0) { Data d(&m(0,0),m.nrows()*m.ncols()); pointer=d.pointer; size=d.size; type=d.type; } + else { pointer=NULL; size=0; } } /// Init from reference to std::string - explicit Data(std::string&s){ - if(s.size()>0){ Data d(&s[0],s.size()); pointer=d.pointer; size=d.size; type=d.type; } + explicit Data(std::string&s) { + if(s.size()>0) { Data d(&s[0],s.size()); pointer=d.pointer; size=d.size; type=d.type; } else { pointer=NULL; size=0; } } }; /// Const version of Communicator::Data /// See Communicator::Data documentation - struct ConstData{ + struct ConstData { const void*pointer; int size; MPI_Datatype type; @@ -106,27 +106,27 @@ class Communicator{ template <unsigned n> explicit ConstData(const VectorGeneric<n> &p): pointer(&p), size(n), type(getMPIType<double>()) {} template <unsigned n,unsigned m> explicit ConstData(const TensorGeneric<n,m> *p,int s): pointer(p), size(n*m*s), type(getMPIType<double>()) {} template <unsigned n,unsigned m> explicit ConstData(const TensorGeneric<n,m> &p): pointer(&p), size(n*m), type(getMPIType<double>()) {} - template <typename T> explicit ConstData(const std::vector<T>&v){ - if(v.size()>0){ ConstData d(&v[0],v.size()); pointer=d.pointer; size=d.size; type=d.type; } + template <typename T> explicit ConstData(const std::vector<T>&v) { + if(v.size()>0) { ConstData d(&v[0],v.size()); pointer=d.pointer; size=d.size; type=d.type; } else { pointer=NULL; size=0; } } - template <typename T> explicit ConstData(const Matrix<T>&m ){ - if(m.nrows()*m.ncols()>0){ ConstData d(&m(0,0),m.nrows()*m.ncols()); pointer=d.pointer; size=d.size; type=d.type; } - else{ pointer=NULL; size=0; } + template <typename T> explicit ConstData(const Matrix<T>&m ) { + if(m.nrows()*m.ncols()>0) { ConstData d(&m(0,0),m.nrows()*m.ncols()); pointer=d.pointer; size=d.size; type=d.type; } + else { pointer=NULL; size=0; } } - explicit ConstData(const std::string&s){ - if(s.size()>0){ ConstData d(&s[0],s.size()); pointer=d.pointer; size=d.size; type=d.type; } + explicit ConstData(const std::string&s) { + if(s.size()>0) { ConstData d(&s[0],s.size()); pointer=d.pointer; size=d.size; type=d.type; } else { pointer=NULL; size=0; } } }; public: /// Wrapper class for MPI_Status - class Status{ + class Status { int Get_count(MPI_Datatype)const; public: MPI_Status s; template <class T> - int Get_count()const{return Get_count(getMPIType<T>());} + int Get_count()const {return Get_count(getMPIType<T>());} }; /// Special status used when status should be ignored. /// E.g. `Recv(a,0,1,Communicator::StatusIgnore);` @@ -134,7 +134,7 @@ public: /// `Recv(a,0,1);` static Status StatusIgnore; /// Wrapper class for MPI_Request - class Request{ + class Request { public: MPI_Request r; void wait(Status&s=StatusIgnore); @@ -178,50 +178,52 @@ public: /// Wrapper for MPI_Allreduce with MPI_SUM (data struct) void Sum(Data); /// Wrapper for MPI_Allreduce with MPI_SUM (pointer) - template <class T> void Sum(T*buf,int count){Sum(Data(buf,count));} + template <class T> void Sum(T*buf,int count) {Sum(Data(buf,count));} /// Wrapper for MPI_Allreduce with MPI_SUM (reference) - template <class T> void Sum(T&buf){Sum(Data(buf));} + template <class T> void Sum(T&buf) {Sum(Data(buf));} /// Wrapper for MPI_Bcast (data struct) void Bcast(Data,int); /// Wrapper for MPI_Bcast (pointer) - template <class T> void Bcast(T*buf,int count,int root){Bcast(Data(buf,count),root);} + template <class T> void Bcast(T*buf,int count,int root) {Bcast(Data(buf,count),root);} /// Wrapper for MPI_Bcast (reference) - template <class T> void Bcast(T&buf,int root){Bcast(Data(buf),root);} + template <class T> void Bcast(T&buf,int root) {Bcast(Data(buf),root);} /// Wrapper for MPI_Isend (data struct) Request Isend(ConstData,int,int); /// Wrapper for MPI_Isend (pointer) - template <class T> Request Isend(const T*buf,int count,int source,int tag){return Isend(ConstData(buf,count),source,tag);} + template <class T> Request Isend(const T*buf,int count,int source,int tag) {return Isend(ConstData(buf,count),source,tag);} /// Wrapper for MPI_Isend (reference) - template <class T> Request Isend(const T&buf,int source,int tag){return Isend(ConstData(buf),source,tag);} + template <class T> Request Isend(const T&buf,int source,int tag) {return Isend(ConstData(buf),source,tag);} /// Wrapper for MPI_Allgatherv (data struct) void Allgatherv(ConstData in,Data out,const int*,const int*); /// Wrapper for MPI_Allgatherv (pointer) - template <class T,class S> void Allgatherv(const T*sendbuf,int sendcount,S*recvbuf,const int*recvcounts,const int*displs){ - Allgatherv(ConstData(sendbuf,sendcount),Data(recvbuf,0),recvcounts,displs);} + template <class T,class S> void Allgatherv(const T*sendbuf,int sendcount,S*recvbuf,const int*recvcounts,const int*displs) { + Allgatherv(ConstData(sendbuf,sendcount),Data(recvbuf,0),recvcounts,displs); + } /// Wrapper for MPI_Allgatherv (reference) - template <class T,class S> void Allgatherv(const T&sendbuf,S&recvbuf,const int*recvcounts,const int*displs){ - Allgatherv(ConstData(sendbuf),Data(recvbuf),recvcounts,displs);} + template <class T,class S> void Allgatherv(const T&sendbuf,S&recvbuf,const int*recvcounts,const int*displs) { + Allgatherv(ConstData(sendbuf),Data(recvbuf),recvcounts,displs); + } /// Wrapper for MPI_Allgather (data struct) void Allgather(ConstData in,Data out); /// Wrapper for MPI_Allgatherv (pointer) - template <class T,class S> void Allgather(const T*sendbuf,int sendcount,S*recvbuf,int recvcount){ + template <class T,class S> void Allgather(const T*sendbuf,int sendcount,S*recvbuf,int recvcount) { Allgather(ConstData(sendbuf,sendcount),Data(recvbuf,recvcount*Get_size())); } /// Wrapper for MPI_Allgatherv (reference) - template <class T,class S> void Allgather(const T&sendbuf,S&recvbuf){ + template <class T,class S> void Allgather(const T&sendbuf,S&recvbuf) { Allgather(ConstData(sendbuf),Data(recvbuf)); } /// Wrapper for MPI_Recv (data struct) void Recv(Data,int,int,Status&s=StatusIgnore); /// Wrapper for MPI_Recv (pointer) - template <class T> void Recv(T*buf,int count,int source,int tag,Status&s=StatusIgnore){Recv(Data(buf,count),source,tag,s);} + template <class T> void Recv(T*buf,int count,int source,int tag,Status&s=StatusIgnore) {Recv(Data(buf,count),source,tag,s);} /// Wrapper for MPI_Recv (reference) - template <class T> void Recv(T&buf,int source,int tag,Status&s=StatusIgnore){Recv(Data(buf),source,tag,s);} + template <class T> void Recv(T&buf,int source,int tag,Status&s=StatusIgnore) {Recv(Data(buf),source,tag,s);} /// Wrapper to MPI_Comm_split void Split(int,int,Communicator&)const; diff --git a/src/tools/CubicInterpolation.cpp b/src/tools/CubicInterpolation.cpp index e52ba8b62..fd35339bd 100644 --- a/src/tools/CubicInterpolation.cpp +++ b/src/tools/CubicInterpolation.cpp @@ -23,208 +23,209 @@ namespace PLMD { -CInterpolation::CInterpolation( const std::vector<unsigned>& dd, const std::vector<double>& fmin, const std::vector<double>& fmax ) : -bold(0) +CInterpolation::CInterpolation( const std::vector<unsigned>& dd, const std::vector<double>& fmin, const std::vector<double>& fmax ) : + bold(0) { plumed_assert( fmin.size()==dd.size() && fmax.size()==dd.size() ); - + np.resize( dd.size() ); stride.resize( dd.size() ); unsigned totalp=1; - for(unsigned i=0;i<dd.size();++i){ np[i]=dd[i]; stride[dd.size()-1-i]=totalp; totalp*=np[i]; } + for(unsigned i=0; i<dd.size(); ++i) { np[i]=dd[i]; stride[dd.size()-1-i]=totalp; totalp*=np[i]; } - unsigned ii,kk; + unsigned ii,kk; splinepoints.resize( totalp, np.size() ); std::vector<double> delr( np.size() ); - for(unsigned j=0;j<np.size();++j) delr[j] = ( fmax[j] - fmin[j] )/static_cast<double>(np[j]-1); - - for(unsigned i=0;i<totalp;++i){ - ii=i; - for(unsigned j=0;j<np.size();++j){ - kk=std::floor( double(ii) / double(stride[j]) ); - ii-=kk*stride[j]; - splinepoints(i,j)=fmin[j] + kk*delr[j]; - } - plumed_assert(ii==0); + for(unsigned j=0; j<np.size(); ++j) delr[j] = ( fmax[j] - fmin[j] )/static_cast<double>(np[j]-1); + + for(unsigned i=0; i<totalp; ++i) { + ii=i; + for(unsigned j=0; j<np.size(); ++j) { + kk=std::floor( double(ii) / double(stride[j]) ); + ii-=kk*stride[j]; + splinepoints(i,j)=fmin[j] + kk*delr[j]; + } + plumed_assert(ii==0); } lb.resize( np.size() ); ub.resize( np.size() ); } -CInterpolation::~CInterpolation(){ +CInterpolation::~CInterpolation() { splinepoints.resize(0,0); lb.resize(0); ub.resize(0); np.resize(0); stride.resize(0); } void CInterpolation::getNumbersOfPoints( std::vector<unsigned>& nspline ) const { nspline.resize( np.size() ); - for(unsigned i=0;i<np.size();++i) nspline[i]=np[i]; + for(unsigned i=0; i<np.size(); ++i) nspline[i]=np[i]; } -unsigned CInterpolation::findBox( const std::vector<double>& pos ){ +unsigned CInterpolation::findBox( const std::vector<double>& pos ) { plumed_dbg_massert( pos.size()==np.size(), "position size does not match the size of the grid"); unsigned jold, ccf_box, bnew=0; - for(unsigned i=0;i<np.size();++i){ - jold=static_cast<int>( std::floor( double(bold)/double(stride[i]) ) ); - bold-=jold*stride[i]; - ccf_box=search1( i, pos[i], jold ); - bnew+=ccf_box; + for(unsigned i=0; i<np.size(); ++i) { + jold=static_cast<int>( std::floor( double(bold)/double(stride[i]) ) ); + bold-=jold*stride[i]; + ccf_box=search1( i, pos[i], jold ); + bnew+=ccf_box; } plumed_dbg_assert( bold==0 ); bold=bnew; - for(unsigned i=0;i<np.size();++i){ lb[i]=splinepoints(bold,i); ub[i]=splinepoints(bold+stride[i],i); } + for(unsigned i=0; i<np.size(); ++i) { lb[i]=splinepoints(bold,i); ub[i]=splinepoints(bold+stride[i],i); } return bold; } unsigned CInterpolation::search1( const unsigned& kk, const double& x, const unsigned& jold ) const { - int inc=stride[kk], jl=jold*stride[kk], ju=(jold+1)*stride[kk], jm; - if ( x>=splinepoints(jl,kk) && x<splinepoints( ju, kk ) ) return jl; - else { - if( x>=splinepoints(jl, kk ) ){ - while(true){ - ju=jl+inc; - if( x<splinepoints( ju, kk ) ) break; - else if( ju>=(np[kk]-1)*inc ){ju=(np[kk]-1)*inc; break; } - jl=ju; - } - } - else{ - ju=jl; - while(true){ - jl=jl-inc; - if( x>=splinepoints( jl, kk ) ) break; - else if( jl<=0 ){ jl=0; break; } - ju=jl; - } - } + int inc=stride[kk], jl=jold*stride[kk], ju=(jold+1)*stride[kk], jm; + if ( x>=splinepoints(jl,kk) && x<splinepoints( ju, kk ) ) return jl; + else { + if( x>=splinepoints(jl, kk ) ) { + while(true) { + ju=jl+inc; + if( x<splinepoints( ju, kk ) ) break; + else if( ju>=(np[kk]-1)*inc ) {ju=(np[kk]-1)*inc; break; } + jl=ju; + } } - while( ju-jl>inc ){ - jm = (ju+jl) / (2*inc) ; - if ( x>splinepoints(jm*inc,kk) ) jl=jm*inc; else ju=jm*inc; + else { + ju=jl; + while(true) { + jl=jl-inc; + if( x>=splinepoints( jl, kk ) ) break; + else if( jl<=0 ) { jl=0; break; } + ju=jl; + } } - plumed_dbg_assert( jl%stride[kk]==0 && ju==jl+stride[kk] ); - return jl; + } + while( ju-jl>inc ) { + jm = (ju+jl) / (2*inc) ; + if ( x>splinepoints(jm*inc,kk) ) jl=jm*inc; else ju=jm*inc; + } + plumed_dbg_assert( jl%stride[kk]==0 && ju==jl+stride[kk] ); + return jl; } InterpolateCubic::InterpolateCubic( const std::vector<unsigned>& dd, const std::vector<double>& fmin, const std::vector<double>& fmax ) : -CInterpolation(dd,fmin,fmax) + CInterpolation(dd,fmin,fmax) { plumed_massert(np.size()==1,"should be one dimensional data"); clist.resize( 4*np[0] ); } -void InterpolateCubic::set_table( const std::vector<Value>& ff ){ - plumed_assert( getNumberOfSplinePoints()==ff.size() ); +void InterpolateCubic::set_table( const std::vector<Value>& ff ) { + plumed_assert( getNumberOfSplinePoints()==ff.size() ); plumed_assert( ff[0].getNumberOfDerivatives()==1 ); double d1, norm; unsigned pij; - for(unsigned i=0;i<np[0]-1;++i){ - d1 = getPointSpacing( 0, i ); - norm=(d1*d1)/6.0; pij=i*4; - clist[pij]=ff[i].get(); pij++; - clist[pij]=ff[i+1].get(); pij++; - clist[pij]=ff[i].getDerivative(0)*norm; pij++; - clist[pij]=ff[i+1].getDerivative(0)*norm; + for(unsigned i=0; i<np[0]-1; ++i) { + d1 = getPointSpacing( 0, i ); + norm=(d1*d1)/6.0; pij=i*4; + clist[pij]=ff[i].get(); pij++; + clist[pij]=ff[i+1].get(); pij++; + clist[pij]=ff[i].getDerivative(0)*norm; pij++; + clist[pij]=ff[i+1].getDerivative(0)*norm; } } -double InterpolateCubic::get_fdf( const std::vector<double>& pos ){ +double InterpolateCubic::get_fdf( const std::vector<double>& pos ) { plumed_dbg_assert( pos.size()==1 ); - + unsigned mybox=findBox( pos ); - double d1=ub[0] - lb[0]; + double d1=ub[0] - lb[0]; double b=( pos[0] - lb[0] ) / d1, a=( ub[0] - pos[0] ) / d1; - + double *cbase=&clist[(mybox*4)+3], *c3=cbase-1, *c2=c3-1, *c1=c2-1; double f=a*(*c1) + b*(*c2) + (a*a*a-a)*(*c3) + (b*b*b-b)*(*cbase); - return f; + return f; } InterpolateBicubic::InterpolateBicubic( const std::vector<unsigned>& dd, const std::vector<double>& fmin, const std::vector<double>& fmax ) : -CInterpolation(dd,fmin,fmax) + CInterpolation(dd,fmin,fmax) { plumed_massert(np.size()==2,"should be two dimensional data"); static int wt_d[16*16]= - {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, - -3, 0, 0, 3, 0, 0, 0, 0,-2, 0, 0,-1, 0, 0, 0, 0, - 2, 0, 0,-2, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0,-3, 0, 0, 3, 0, 0, 0, 0,-2, 0, 0,-1, - 0, 0, 0, 0, 2, 0, 0,-2, 0, 0, 0, 0, 1, 0, 0, 1, - -3, 3, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0,-2,-1, 0, 0, - 9,-9, 9,-9, 6, 3,-3,-6, 6,-6,-3, 3, 4, 2, 1, 2, - -6, 6,-6, 6,-4,-2, 2, 4,-3, 3, 3,-3,-2,-1,-1,-2, - 2,-2, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 1, 1, 0, 0, - -6, 6,-6, 6,-3,-3, 3, 3,-4, 4, 2,-2,-2,-2,-1,-1, - 4,-4, 4,-4, 2, 2,-2,-2, 2,-2,-2, 2, 1, 1, 1, 1}; + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + -3, 0, 0, 3, 0, 0, 0, 0,-2, 0, 0,-1, 0, 0, 0, 0, + 2, 0, 0,-2, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0,-3, 0, 0, 3, 0, 0, 0, 0,-2, 0, 0,-1, + 0, 0, 0, 0, 2, 0, 0,-2, 0, 0, 0, 0, 1, 0, 0, 1, + -3, 3, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0,-2,-1, 0, 0, + 9,-9, 9,-9, 6, 3,-3,-6, 6,-6,-3, 3, 4, 2, 1, 2, + -6, 6,-6, 6,-4,-2, 2, 4,-3, 3, 3,-3,-2,-1,-1,-2, + 2,-2, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 1, 1, 0, 0, + -6, 6,-6, 6,-3,-3, 3, 3,-4, 4, 2,-2,-2,-2,-1,-1, + 4,-4, 4,-4, 2, 2,-2,-2, 2,-2,-2, 2, 1, 1, 1, 1 + }; // This is to set up the coefficient matrix unsigned l=0; wt.resize(16,16); t1.resize(16); t2.resize(16); - for (unsigned i=0;i<16;i++) for (unsigned j=0;j<16;j++){ wt(i,j)=wt_d[l++]; } + for (unsigned i=0; i<16; i++) for (unsigned j=0; j<16; j++) { wt(i,j)=wt_d[l++]; } // Resize everything dcross.resize( np[0], np[1] ); clist.resize( np[0] * np[1] * 4 * 4 ); } -void InterpolateBicubic::set_table( const std::vector<Value>& ff ){ - plumed_assert( getNumberOfSplinePoints()==ff.size() ); +void InterpolateBicubic::set_table( const std::vector<Value>& ff ) { + plumed_assert( getNumberOfSplinePoints()==ff.size() ); plumed_assert( ff[0].getNumberOfDerivatives()==2 ); dcross=0.0; unsigned iplus, iminus; - for(unsigned i=1;i<np[0]-1;++i){ - iplus=(i+1)*stride[0]; iminus=(i-1)*stride[0]; - for(unsigned j=1;j<np[1]-1;++j){ - dcross(i,j) = ( ff[iplus+j+1].get() + ff[iminus+j-1].get() - ff[iplus+j-1].get() - ff[iminus+j+1].get() ) / - getCrossTermDenominator( i, j ); - } - } + for(unsigned i=1; i<np[0]-1; ++i) { + iplus=(i+1)*stride[0]; iminus=(i-1)*stride[0]; + for(unsigned j=1; j<np[1]-1; ++j) { + dcross(i,j) = ( ff[iplus+j+1].get() + ff[iminus+j-1].get() - ff[iplus+j-1].get() - ff[iminus+j+1].get() ) / + getCrossTermDenominator( i, j ); + } + } double d1, d2; Matrix<double> tc(4,4); std::vector<double> y(4), dy1(4), dy2(4), d2y12(4); unsigned pij=0; unsigned ipos; - for (unsigned i=0;i<np[0]-1;++i){ - ipos=i*stride[0]; d1 = getPointSpacing( 0, i ); - for (unsigned j=0; j<np[1]-1;++j){ - d2 = getPointSpacing( 1, j ); - y[0] = ff[ipos+j].get(); y[1] = ff[ipos+stride[0]+j].get(); y[2] = ff[ipos+stride[0]+j+1].get(); y[3] = ff[ipos+j+1].get(); - dy1[0] = ff[ipos+j].getDerivative(0); dy1[1] = ff[ipos+stride[0]+j].getDerivative(0); - dy1[2] = ff[ipos+stride[0]+j+1].getDerivative(0); dy1[3] = ff[ipos+j+1].getDerivative(0); - dy2[0] = ff[ipos+j].getDerivative(1); dy2[1] = ff[ipos+stride[0]+j].getDerivative(1); - dy2[2] = ff[ipos+stride[0]+j+1].getDerivative(1); dy2[3] = ff[ipos+j+1].getDerivative(1); - d2y12[0] = dcross( i, j ); d2y12[1] = dcross( i+1, j ); d2y12[2] = dcross( i+1, j+1 ); d2y12[3] = dcross( i, j+1 ); - IBicCoeff( y, dy1, dy2, d2y12, d1, d2, tc); - - pij=( ipos+j )*16; - for(unsigned k=0; k<4; ++k){ for(unsigned n=0; n<4; ++n){ clist[pij++]=tc(k,n); } } - } + for (unsigned i=0; i<np[0]-1; ++i) { + ipos=i*stride[0]; d1 = getPointSpacing( 0, i ); + for (unsigned j=0; j<np[1]-1; ++j) { + d2 = getPointSpacing( 1, j ); + y[0] = ff[ipos+j].get(); y[1] = ff[ipos+stride[0]+j].get(); y[2] = ff[ipos+stride[0]+j+1].get(); y[3] = ff[ipos+j+1].get(); + dy1[0] = ff[ipos+j].getDerivative(0); dy1[1] = ff[ipos+stride[0]+j].getDerivative(0); + dy1[2] = ff[ipos+stride[0]+j+1].getDerivative(0); dy1[3] = ff[ipos+j+1].getDerivative(0); + dy2[0] = ff[ipos+j].getDerivative(1); dy2[1] = ff[ipos+stride[0]+j].getDerivative(1); + dy2[2] = ff[ipos+stride[0]+j+1].getDerivative(1); dy2[3] = ff[ipos+j+1].getDerivative(1); + d2y12[0] = dcross( i, j ); d2y12[1] = dcross( i+1, j ); d2y12[2] = dcross( i+1, j+1 ); d2y12[3] = dcross( i, j+1 ); + IBicCoeff( y, dy1, dy2, d2y12, d1, d2, tc); + + pij=( ipos+j )*16; + for(unsigned k=0; k<4; ++k) { for(unsigned n=0; n<4; ++n) { clist[pij++]=tc(k,n); } } + } } } -void InterpolateBicubic::IBicCoeff( const std::vector<double>& y, const std::vector<double>& dy1, const std::vector<double>& dy2, - const std::vector<double>& d2y12, const double& d1, const double& d2, Matrix<double>& c ){ +void InterpolateBicubic::IBicCoeff( const std::vector<double>& y, const std::vector<double>& dy1, const std::vector<double>& dy2, + const std::vector<double>& d2y12, const double& d1, const double& d2, Matrix<double>& c ) { double xx, d1d2=d1*d2; - for(unsigned i=0;i<4;i++){ t1[i] = y[i]; t1[i+4] = dy1[i]*d1; t1[i+8] = dy2[i]*d2; t1[i+12] = d2y12[i]*d1d2; } - for(unsigned i=0;i<16;i++){ xx=0.0; for(unsigned k=0;k<16;k++){ xx += wt(i,k)*t1[k]; } t2[i]=xx; } - unsigned l=0; for(unsigned i=0;i<4;i++){ for(unsigned j=0;j<4;j++){ c(i,j)=t2[l++]; } } + for(unsigned i=0; i<4; i++) { t1[i] = y[i]; t1[i+4] = dy1[i]*d1; t1[i+8] = dy2[i]*d2; t1[i+12] = d2y12[i]*d1d2; } + for(unsigned i=0; i<16; i++) { xx=0.0; for(unsigned k=0; k<16; k++) { xx += wt(i,k)*t1[k]; } t2[i]=xx; } + unsigned l=0; for(unsigned i=0; i<4; i++) { for(unsigned j=0; j<4; j++) { c(i,j)=t2[l++]; } } } -double InterpolateBicubic::get_fdf( const std::vector<double>& pos ){ +double InterpolateBicubic::get_fdf( const std::vector<double>& pos ) { - plumed_dbg_assert( pos.size()==2 ); - unsigned mybox=findBox( pos ); - double d1 = ub[0] - lb[0], d2 = ub[1] - lb[1]; - double t = (pos[0] - lb[0]) / d1, u = (pos[1] - lb[1]) / d2; + plumed_dbg_assert( pos.size()==2 ); + unsigned mybox=findBox( pos ); + double d1 = ub[0] - lb[0], d2 = ub[1] - lb[1]; + double t = (pos[0] - lb[0]) / d1, u = (pos[1] - lb[1]) / d2; - //faster access by pointer arithmetic (dirty dirty dirty) - double *cbase=&clist[(mybox+1)*16-1], *c3, *c2, *c1, *c0; + //faster access by pointer arithmetic (dirty dirty dirty) + double *cbase=&clist[(mybox+1)*16-1], *c3, *c2, *c1, *c0; - double f=0.; - for (int i=3; i>=0; i--) { // Note to self - this has to be an int as unsigned cannot be less than zero - duh!! - c3=cbase; c2=c3-1; c1=c2-1; c0=c1-1; cbase=c0-1; - f= t*f + ( ( (*c3)*u + (*c2) )*u + (*c1) )*u + (*c0); - } - delete cbase; delete c3; delete c2; delete c1; delete c0; - return f; + double f=0.; + for (int i=3; i>=0; i--) { // Note to self - this has to be an int as unsigned cannot be less than zero - duh!! + c3=cbase; c2=c3-1; c1=c2-1; c0=c1-1; cbase=c0-1; + f= t*f + ( ( (*c3)*u + (*c2) )*u + (*c1) )*u + (*c0); + } + delete cbase; delete c3; delete c2; delete c1; delete c0; + return f; } } diff --git a/src/tools/CubicInterpolation.h b/src/tools/CubicInterpolation.h index 39ecca968..fdbdcc361 100644 --- a/src/tools/CubicInterpolation.h +++ b/src/tools/CubicInterpolation.h @@ -59,13 +59,13 @@ unsigned CInterpolation::getNumberOfSplinePoints() const { inline void CInterpolation::getSplinePoint( const unsigned nn, std::vector<double>& pp ) const { plumed_dbg_assert( nn<splinepoints.nrows() && pp.size()==np.size() ); - for(unsigned i=0;i<np.size();++i) pp[i]=splinepoints(nn,i); + for(unsigned i=0; i<np.size(); ++i) pp[i]=splinepoints(nn,i); } inline double CInterpolation::getPointSpacing( const unsigned dir, const unsigned k ) const { unsigned i=k*stride[dir]; - return splinepoints(i+stride[dir], dir) - splinepoints(i, dir); + return splinepoints(i+stride[dir], dir) - splinepoints(i, dir); } inline diff --git a/src/tools/DLLoader.cpp b/src/tools/DLLoader.cpp index 1d2a7d802..b56e4c236 100644 --- a/src/tools/DLLoader.cpp +++ b/src/tools/DLLoader.cpp @@ -25,9 +25,9 @@ #include <dlfcn.h> #endif -namespace PLMD{ +namespace PLMD { -bool DLLoader::installed(){ +bool DLLoader::installed() { #ifdef __PLUMED_HAS_DLOPEN return true; #else @@ -36,10 +36,10 @@ bool DLLoader::installed(){ } -void* DLLoader::load(const std::string&s){ +void* DLLoader::load(const std::string&s) { #ifdef __PLUMED_HAS_DLOPEN void* p=dlopen(s.c_str(),RTLD_NOW|RTLD_LOCAL); - if(!p){ + if(!p) { lastError=dlerror(); } else { lastError=""; @@ -51,20 +51,20 @@ void* DLLoader::load(const std::string&s){ #endif } -const std::string & DLLoader::error(){ +const std::string & DLLoader::error() { return lastError; } -DLLoader::~DLLoader(){ +DLLoader::~DLLoader() { #ifdef __PLUMED_HAS_DLOPEN - while(!handles.empty()){ + while(!handles.empty()) { dlclose(handles.top()); handles.pop(); } #endif } -DLLoader::DLLoader(){ +DLLoader::DLLoader() { // do nothing } diff --git a/src/tools/DLLoader.h b/src/tools/DLLoader.h index f2f76d0fa..fdad73f2a 100644 --- a/src/tools/DLLoader.h +++ b/src/tools/DLLoader.h @@ -25,7 +25,7 @@ #include <stack> #include <string> -namespace PLMD{ +namespace PLMD { /// \ingroup TOOLBOX /// Class taking care of dynamic loading. @@ -37,7 +37,7 @@ namespace PLMD{ /// means that they are not accessible from outside. Still, if they /// contain self-registering classes, they will register themselves /// to the ActionRegister object. -class DLLoader{ +class DLLoader { std::stack<void*> handles; std::string lastError; /// Private copy constructor diff --git a/src/tools/DynamicList.h b/src/tools/DynamicList.h index 2f006dcf5..c5252de5b 100644 --- a/src/tools/DynamicList.h +++ b/src/tools/DynamicList.h @@ -30,7 +30,7 @@ namespace PLMD { /** \ingroup TOOLBOX A class for storing a list that changes which members are active as a function of time. It also -contains friends method that allows you to link two dynamic lists so that you can request +contains friends method that allows you to link two dynamic lists so that you can request stuff from list2 in list1 A PLMD::DynamicList can be used to change what elements in a list should be looped over at any given time. This class is, for the most part, used in tandem with PLMD::NeighbourList. For complex reasons @@ -56,10 +56,10 @@ aa to do at a given time. This is done by: \verbatim DynamicList list; std::vector<something> aa; unsigned kk; for(unsigned i=0;i<list.getNumberActive();++i){ kk=list[i]; aa[kk].doSomething(); } -\endverbatim +\endverbatim -where we somewhere set up the list and make some decisions (in PLMD::NeighbourList for example) as to what elements -from aa are currently active. +where we somewhere set up the list and make some decisions (in PLMD::NeighbourList for example) as to what elements +from aa are currently active. \section Setup @@ -69,7 +69,7 @@ above with aa one can do this using: \verbatim DynamicList list; for(unsigned i=0;i<aa.size();++i) list.addIndexToList( i ); -\endverbatim +\endverbatim Doing this creates the list of all members. @@ -110,9 +110,9 @@ PLMD::DynamicList::updateActiveMembers(). Once this is done you can loop over o made active using: \verbatim -DynamicList list; +DynamicList list; for(unsigned i=0;i<list.getNumberActive();++i){ kk=list[i]; aa[kk].doSomething(); } -\endverbatim +\endverbatim as was described above. @@ -120,13 +120,13 @@ as was described above. If your loop is distributed over processesors you can still use dynamic lists to activate and deactivate members. When running with mpi however you must call PLMD::DynamicList::setupMPICommunication during initialization. To -gather the members that have been activated/deactivated during the running of all the processes on all the nodes +gather the members that have been activated/deactivated during the running of all the processes on all the nodes you must call PLMD::DynamicList::mpi_gatherActiveMembers in place of PLMD::DynamicList::updateActiveMembers. \section arse4 A final note When using dynamic_lists we strongly recommend that you first compile without the -DNDEBUG flag. When this -flag is not present many checks are performed inside the dynamic list class, which will help you ensure that +flag is not present many checks are performed inside the dynamic list class, which will help you ensure that the dynamic list is used correctly. */ @@ -134,8 +134,8 @@ the dynamic list is used correctly. template <typename T> class DynamicList { /// This gathers data split across nodes list of Dynamic lists -template <typename U> -friend void mpi_gatherActiveMembers(Communicator& , std::vector< DynamicList<U> >& ); + template <typename U> + friend void mpi_gatherActiveMembers(Communicator&, std::vector< DynamicList<U> >& ); private: /// This is the list of all the relevent members std::vector<T> all; @@ -155,14 +155,14 @@ public: /// Constructor DynamicList():nactive(0),nprocessors(1),rank(0),allWereActivated(false),allWereDeactivated(false) {} /// An operator that returns the element from the current active list - inline T operator [] (const unsigned& i) const { - plumed_dbg_assert( i<nactive ); - return all[ active[i] ]; + inline T operator [] (const unsigned& i) const { + plumed_dbg_assert( i<nactive ); + return all[ active[i] ]; } /// An operator that returns the element from the full list (used in neighbour lists) inline T operator () (const unsigned& i) const { - plumed_dbg_assert( i<all.size() ); - return all[i]; + plumed_dbg_assert( i<all.size() ); + return all[i]; } /// Clear the list void clear(); @@ -181,7 +181,7 @@ public: /// Find the index of in the list which has value t int getIndexOfElement( const T& t ) const ; /// Make a particular element inactive - void deactivate( const T& t ); + void deactivate( const T& t ); /// Make everything in the list inactive void deactivateAll(); /// Make something active @@ -204,19 +204,19 @@ public: /// This sorts the elements in the active list void sortActiveList(); /// Retriee the list of active objects - std::vector<T> retrieveActiveList(); + std::vector<T> retrieveActiveList(); }; template <typename T> -std::vector<T> DynamicList<T>::retrieveActiveList(){ +std::vector<T> DynamicList<T>::retrieveActiveList() { std::vector<T> this_active(nactive); - for(unsigned k=0;k<nactive;++k) this_active[k]=all[ active[k] ]; + for(unsigned k=0; k<nactive; ++k) this_active[k]=all[ active[k] ]; return this_active; } template <typename T> void DynamicList<T>::clear() { - all.resize(0); + all.resize(0); onoff.resize(0); active.resize(0); } @@ -236,105 +236,105 @@ unsigned DynamicList<T>::getNumberActive() const { } template <typename T> -void DynamicList<T>::addIndexToList( const T & ii ){ - all.push_back(ii); active.resize( all.size() ); onoff.push_back(0); +void DynamicList<T>::addIndexToList( const T & ii ) { + all.push_back(ii); active.resize( all.size() ); onoff.push_back(0); } template <typename T> -void DynamicList<T>::createIndexListFromVector( const std::vector<T>& myind ){ +void DynamicList<T>::createIndexListFromVector( const std::vector<T>& myind ) { plumed_dbg_assert( all.size()==0 ); onoff.resize( myind.size(), 0 ); - active.resize( myind.size() ); + active.resize( myind.size() ); all.insert( all.end(), myind.begin(), myind.end() ); } template <typename T> -void DynamicList<T>::setupMPICommunication( Communicator& comm ){ +void DynamicList<T>::setupMPICommunication( Communicator& comm ) { nprocessors=comm.Get_size(); rank=comm.Get_rank(); } template <typename T> int DynamicList<T>::getIndexOfElement( const T& t ) const { - for(unsigned i=0;i<all.size();++i){ - if( t==all[i] ){return i; } + for(unsigned i=0; i<all.size(); ++i) { + if( t==all[i] ) {return i; } } plumed_merror("Could not find an element in the dynamic list"); return 0; } template <typename T> -void DynamicList<T>::deactivate( const T& t ){ +void DynamicList<T>::deactivate( const T& t ) { plumed_dbg_assert( allWereActivated ); unsigned ii=getIndexOfElement( t ); if( onoff[ii]==0 || onoff[ii]%nprocessors!=0 ) return; // Deactivates the component if( rank==0 ) onoff[ii]=nprocessors-1; - else onoff[ii]=nprocessors-rank; + else onoff[ii]=nprocessors-rank; } template <typename T> -void DynamicList<T>::deactivateAll(){ +void DynamicList<T>::deactivateAll() { allWereDeactivated=true; allWereActivated=false; - for(unsigned i=0;i<nactive;++i) onoff[ active[i] ]= 0; + for(unsigned i=0; i<nactive; ++i) onoff[ active[i] ]= 0; nactive=0; #ifndef NDEBUG - for(unsigned i=0;i<onoff.size();++i) plumed_dbg_assert( onoff[i]==0 ); + for(unsigned i=0; i<onoff.size(); ++i) plumed_dbg_assert( onoff[i]==0 ); #endif } template <typename T> -void DynamicList<T>::activate( const unsigned ii ){ +void DynamicList<T>::activate( const unsigned ii ) { plumed_dbg_massert(ii<all.size(),"ii is out of bounds"); plumed_dbg_assert( !allWereActivated ); onoff[ii]=nprocessors; } template <typename T> -void DynamicList<T>::activateAll(){ - for(unsigned i=0;i<onoff.size();++i) onoff[i]=nprocessors; - allWereActivated=true; updateActiveMembers(); allWereActivated=true; - +void DynamicList<T>::activateAll() { + for(unsigned i=0; i<onoff.size(); ++i) onoff[i]=nprocessors; + allWereActivated=true; updateActiveMembers(); allWereActivated=true; + } template <typename T> -void DynamicList<T>::mpi_gatherActiveMembers(Communicator& comm){ +void DynamicList<T>::mpi_gatherActiveMembers(Communicator& comm) { plumed_massert( comm.Get_size()==nprocessors, "error missing a call to DynamicList::setupMPICommunication"); comm.Sum(&onoff[0],onoff.size()); // When we mpi gather onoff to be on it should be active on ALL nodes - for(unsigned i=0;i<all.size();++i) if( onoff[i]>0 && onoff[i]%nprocessors==0 ){ onoff[i]=nprocessors; } + for(unsigned i=0; i<all.size(); ++i) if( onoff[i]>0 && onoff[i]%nprocessors==0 ) { onoff[i]=nprocessors; } updateActiveMembers(); } template <typename T> -void DynamicList<T>::updateActiveMembers(){ +void DynamicList<T>::updateActiveMembers() { plumed_dbg_assert( allWereActivated || allWereDeactivated ); unsigned kk=0; allWereActivated=allWereDeactivated=false; - for(unsigned i=0;i<all.size();++i){ - if( onoff[i]>0 && onoff[i]%nprocessors==0 ){ active[kk]=i; kk++; } + for(unsigned i=0; i<all.size(); ++i) { + if( onoff[i]>0 && onoff[i]%nprocessors==0 ) { active[kk]=i; kk++; } } - nactive=kk; + nactive=kk; } template <typename T> -void DynamicList<T>::emptyActiveMembers(){ +void DynamicList<T>::emptyActiveMembers() { plumed_dbg_assert( allWereActivated || allWereDeactivated ); nactive=0; } template <typename T> -void DynamicList<T>::putIndexInActiveArray( const unsigned& ii ){ +void DynamicList<T>::putIndexInActiveArray( const unsigned& ii ) { plumed_dbg_assert( allWereActivated || allWereDeactivated ); plumed_dbg_assert( onoff[ii]>0 && onoff[ii]%nprocessors==0 ); active[nactive]=ii; nactive++; } template <typename T> -void DynamicList<T>::completeUpdate(){ +void DynamicList<T>::completeUpdate() { plumed_dbg_assert( allWereActivated || allWereDeactivated ); allWereActivated=allWereDeactivated=false; } template <typename T> -void DynamicList<T>::sortActiveList(){ +void DynamicList<T>::sortActiveList() { plumed_dbg_assert( allWereActivated || allWereDeactivated ); allWereActivated=allWereDeactivated=false; std::sort( active.begin(), active.begin()+nactive ); @@ -347,31 +347,31 @@ bool DynamicList<T>::updateComplete() const { } template <typename U> -void mpi_gatherActiveMembers(Communicator& comm, std::vector< DynamicList<U> >& ll ){ +void mpi_gatherActiveMembers(Communicator& comm, std::vector< DynamicList<U> >& ll ) { // Setup an array to hold all data unsigned bufsize=0; unsigned size=comm.Get_size(); - for(unsigned i=0;i<ll.size();++i){ - plumed_dbg_massert( ll[i].nprocessors==size, "missing a call to DynamicList::setupMPICommunication" ); - bufsize+=ll[i].onoff.size(); + for(unsigned i=0; i<ll.size(); ++i) { + plumed_dbg_massert( ll[i].nprocessors==size, "missing a call to DynamicList::setupMPICommunication" ); + bufsize+=ll[i].onoff.size(); } std::vector<unsigned> buffer( bufsize ); // Gather all onoff data into a single array bufsize=0; - for(unsigned i=0;i<ll.size();++i){ - for(unsigned j=0;j<ll[i].onoff.size();++j){ buffer[bufsize]=ll[i].onoff[j]; bufsize++; } + for(unsigned i=0; i<ll.size(); ++i) { + for(unsigned j=0; j<ll[i].onoff.size(); ++j) { buffer[bufsize]=ll[i].onoff[j]; bufsize++; } } // GATHER from all nodes comm.Sum(&buffer[0],buffer.size()); // distribute back to original lists - bufsize=0; - for(unsigned i=0;i<ll.size();++i){ - for(unsigned j=0;j<ll[i].onoff.size();++j){ - if( buffer[bufsize]>0 && buffer[bufsize]%size==0 ) ll[i].onoff[j]=size; - else ll[i].onoff[j]=size-1; - bufsize++; - } + bufsize=0; + for(unsigned i=0; i<ll.size(); ++i) { + for(unsigned j=0; j<ll[i].onoff.size(); ++j) { + if( buffer[bufsize]>0 && buffer[bufsize]%size==0 ) ll[i].onoff[j]=size; + else ll[i].onoff[j]=size-1; + bufsize++; + } } - for(unsigned i=0;i<ll.size();++i) ll[i].updateActiveMembers(); + for(unsigned i=0; i<ll.size(); ++i) ll[i].updateActiveMembers(); } } diff --git a/src/tools/ERMSD.cpp b/src/tools/ERMSD.cpp index 398d6a517..65c9da9f2 100644 --- a/src/tools/ERMSD.cpp +++ b/src/tools/ERMSD.cpp @@ -36,296 +36,296 @@ using namespace std; -namespace PLMD{ +namespace PLMD { - - void ERMSD::clear(){ - reference_mat.clear(); - } - //void ERMSD::calcLcs(const vector<Vector> & positions, vector<Vector> &) +void ERMSD::clear() { + reference_mat.clear(); +} - void ERMSD::setReference(const vector<Vector> & reference, const std::vector<unsigned> & pairs_vec, double mycutoff){ +//void ERMSD::calcLcs(const vector<Vector> & positions, vector<Vector> &) - - natoms = reference.size(); - nresidues = natoms/3; - unsigned npairs = pairs_vec.size()/2; - pairs.resize(npairs); - //for(unsigned i=0;i<2*npairs;++i) { - // std::cout << "CCC " << pairs_vec[i] << " "; - //} - for(unsigned i=0;i<npairs;++i) { +void ERMSD::setReference(const vector<Vector> & reference, const std::vector<unsigned> & pairs_vec, double mycutoff) { - pairs[i].first = pairs_vec[2*i]; - pairs[i].second = pairs_vec[2*i+1]; - } - cutoff = mycutoff; - std::vector<TensorGeneric<4,3> > deri; - deri.resize(natoms*natoms); - reference_mat.resize(nresidues*nresidues); - Pbc fake_pbc; - - - calcMat(reference,fake_pbc,reference_mat,deri); - - } - - - bool ERMSD::inPair(unsigned i, unsigned j){ - - //return true; - if(pairs.size()==0) return true; - for(unsigned idx=0;idx<pairs.size();idx++){ - //std::cout << "AAA " << pairs[idx][0] << " " << pairs[idx][1] << "\n"; - if(pairs[idx].first == i && pairs[idx].second == j) return true; - if(pairs[idx].second == i && pairs[idx].first == j) return true; - } - return false; - } + natoms = reference.size(); + nresidues = natoms/3; + unsigned npairs = pairs_vec.size()/2; + pairs.resize(npairs); + //for(unsigned i=0;i<2*npairs;++i) { + // std::cout << "CCC " << pairs_vec[i] << " "; + //} + for(unsigned i=0; i<npairs; ++i) { + + pairs[i].first = pairs_vec[2*i]; + pairs[i].second = pairs_vec[2*i+1]; + } + + cutoff = mycutoff; + std::vector<TensorGeneric<4,3> > deri; + deri.resize(natoms*natoms); + reference_mat.resize(nresidues*nresidues); + Pbc fake_pbc; + + + calcMat(reference,fake_pbc,reference_mat,deri); + +} + + +bool ERMSD::inPair(unsigned i, unsigned j) { + + //return true; + if(pairs.size()==0) return true; + for(unsigned idx=0; idx<pairs.size(); idx++) { + //std::cout << "AAA " << pairs[idx][0] << " " << pairs[idx][1] << "\n"; + if(pairs[idx].first == i && pairs[idx].second == j) return true; + if(pairs[idx].second == i && pairs[idx].first == j) return true; + } + return false; +} //double ERMSD::calculate(const std::vector<Vector> & positions, // std::vector<Vector> &derivatives, Tensor& virial) const { // Pbc fake_pbc; // return ERMSD::calculate(positions,fake_pbc,derivatives,virial,false); // } - - - - void ERMSD::calcMat(const std::vector<Vector> & positions,const Pbc& pbc, std::vector<Vector4d> &mat, std::vector<TensorGeneric<4,3> > &Gderi) { - - std::vector<Vector3d> pos; - pos.resize(3*nresidues); - - std::vector<Tensor3d> deri; - deri.resize(nresidues*9); - - std::vector<Vector> centers; - centers.resize(nresidues); - - unsigned idx_deri = 0; - - Tensor da_dxa = (2./3.)*Tensor::identity(); - Tensor da_dxb = -(1./3.)*Tensor::identity(); - Tensor da_dxc = -(1./3.)*Tensor::identity(); - - Tensor db_dxa = -(1./3.)*Tensor::identity(); - Tensor db_dxb = (2./3.)*Tensor::identity(); - Tensor db_dxc = -(1./3.)*Tensor::identity(); - - // Form factors - should this be somewhere else? - - double w = 1./3.; - Vector form_factor = Vector(2.0,2.0,1.0/0.3); - - for(unsigned res_idx=0;res_idx<natoms/3;res_idx++){ - - - const unsigned at_idx = 3*res_idx; - //center - for (unsigned j=0;j<3;j++){ - centers[res_idx] += w*positions[at_idx+j]; - } - - Vector3d a = delta(centers[res_idx],positions[at_idx]); - Vector3d b = delta(centers[res_idx],positions[at_idx+1]); - Vector3d d = crossProduct(a,b); - double ianorm = 1./a.modulo(); - double idnorm = 1./d.modulo(); - - // X vector: COM-C2 - pos[at_idx] = a*ianorm; - // Z versor: C2 x (COM-C4/C6) - pos[at_idx+2] = d*idnorm; - // Y versor: Z x Y - pos[at_idx+1] = crossProduct(pos[at_idx+2],pos[at_idx]); - - // Derivatives //////// - Tensor3d t1 = ianorm*(Tensor::identity()-extProduct(pos[at_idx],pos[at_idx])); - // dv1/dxa - deri[idx_deri] = (2./3. )*t1; - // dv1/dxb - deri[idx_deri+3] = -(1./3.)*t1; - // dv1/dxc - deri[idx_deri+6] = -(1./3.)*t1; - - Tensor dd_dxa = VcrossTensor(a,db_dxa) -VcrossTensor(b,da_dxa); - Tensor dd_dxb = VcrossTensor(a,db_dxb)-VcrossTensor(b,da_dxb); - Tensor dd_dxc = VcrossTensor(a,db_dxc)-VcrossTensor(b,da_dxc); - - // dv3/dxa - deri[idx_deri+2] = deriNorm(d,dd_dxa); - // dv3/dxb - deri[idx_deri+5] = deriNorm(d,dd_dxb); - // dv3/dxc - deri[idx_deri+8] = deriNorm(d,dd_dxc); - - // dv2/dxa = dv3/dxa cross v1 + v3 cross dv1/dxa - deri[idx_deri+1] = (VcrossTensor(deri[idx_deri+2],pos[at_idx]) + \ - VcrossTensor(pos[at_idx+2],deri[idx_deri])); - // dv2/dxb - deri[idx_deri+4] = (VcrossTensor(deri[idx_deri+5],pos[at_idx]) + \ - VcrossTensor(pos[at_idx+2],deri[idx_deri+3])); - // dv2/dxc - deri[idx_deri+7] = (VcrossTensor(deri[idx_deri+8],pos[at_idx]) + \ - VcrossTensor(pos[at_idx+2],deri[idx_deri+6])); - - idx_deri += 9; - // End derivatives /////// - } - - // Initialization (unnecessary?) - for (unsigned i1=0;i1<nresidues*nresidues;i1++){ - for (unsigned i2=0;i2<4;i2++){ - mat[i1][i2] = 0.0; - } - } - double maxdist = cutoff/form_factor[0]; - double gamma = pi/cutoff; - unsigned idx; - unsigned idx1 = 0; - // Calculate mat - for (unsigned i=0;i<nresidues;i++){ - for (unsigned j=0;j<nresidues;j++){ - - // skip i==j - if(inPair(i,j) and i != j){ - //if(i!=j){ - - - // Calculate normal distance first - Vector diff = delta(centers[i],centers[j]); - double d1 = diff.modulo(); - //std::cout << inPair(i,j) << " " << i << " " << j << " "<< d1 <<"\n"; - //std::cout << inPair(i,j) << " " << i << " " << j << " "<< d1 <<"\n"; - if(d1<maxdist){ - - // calculate r_tilde_ij - Vector3d rtilde; - for (unsigned k=0;k<3;k++){ - for (unsigned l=0;l<3;l++){ - rtilde[l] += pos[3*i+l][k]*diff[k]*form_factor[l]; - } - } - double rtilde_norm = rtilde.modulo(); - - double irnorm = 1./rtilde_norm; - - // ellipsoidal cutoff - if(rtilde_norm < cutoff){ - idx = i*nresidues + j; - //std::cout << i << " " << j << " " << rtilde_norm << " " << idx <<"\n"; - - - // fill 4d matrix - double dummy = sin(gamma*rtilde_norm)/(rtilde_norm*gamma); - mat[idx][0] = dummy*rtilde[0]; - mat[idx][1] = dummy*rtilde[1]; - mat[idx][2] = dummy*rtilde[2]; - mat[idx][3] = (1.+ cos(gamma*rtilde_norm))/gamma; - - // Derivative (drtilde_dx) - std::vector<Tensor3d> drtilde_dx; - drtilde_dx.resize(6); - unsigned pos_idx = 3*i; - unsigned deri_idx = 9*i; - for (unsigned at=0;at<3;at++){ - for (unsigned l=0;l<3;l++){ - Vector3d rvec = form_factor[l]*((pos[pos_idx+l])/3.); - Vector3d vvec = form_factor[l]*(matmul(deri[deri_idx+3*at+l],diff)); - drtilde_dx[at].setRow(l,vvec-rvec); - drtilde_dx[at+3].setRow(l,rvec); - } - } - - //std::vector<TensorGeneric<4,3> > dG_dx; - //dG_dx.resize(6); - - double dummy1 = (cos(gamma*rtilde_norm) - dummy); - - idx1 = i*nresidues*6 + j*6; - - for (unsigned l=0;l<6;l++){ - //std::cout << i << " " << j << " " << idx1 << " " << idx1+l << "\n"; - - // components 1,2,3 - // sin(gamma*|rtilde|)/gamma*|rtilde|*d_rtilde + - // + ((d_rtilde*r_tilde/r_tilde^2) out r_tilde)* - // (cos(gamma*|rtilde| - sin(gamma*|rtilde|)/gamma*|rtilde|)) - Vector3d rdr = matmul(rtilde,drtilde_dx[l]); - Tensor tt = dummy*drtilde_dx[l] + (dummy1*irnorm*irnorm)*Tensor(rtilde,rdr); - for (unsigned m=0;m<3;m++){ - // Transpose here - //dG_dx[l].setRow(m,tt.getRow(m)); - Gderi[idx1+l].setRow(m,tt.getRow(m)); - } - // component 4 - // - sin(gamma*|rtilde|)/|rtilde|*(r_tilde*d_rtilde) - //dG_dx[l].setRow(3,-dummy*gamma*rdr); - Gderi[idx1+l].setRow(3,-dummy*gamma*rdr); - } - - - - - } - } - } - - } +void ERMSD::calcMat(const std::vector<Vector> & positions,const Pbc& pbc, std::vector<Vector4d> &mat, std::vector<TensorGeneric<4,3> > &Gderi) { + + std::vector<Vector3d> pos; + pos.resize(3*nresidues); + + std::vector<Tensor3d> deri; + deri.resize(nresidues*9); + + std::vector<Vector> centers; + centers.resize(nresidues); + + unsigned idx_deri = 0; + + Tensor da_dxa = (2./3.)*Tensor::identity(); + Tensor da_dxb = -(1./3.)*Tensor::identity(); + Tensor da_dxc = -(1./3.)*Tensor::identity(); + + Tensor db_dxa = -(1./3.)*Tensor::identity(); + Tensor db_dxb = (2./3.)*Tensor::identity(); + Tensor db_dxc = -(1./3.)*Tensor::identity(); + + // Form factors - should this be somewhere else? + + double w = 1./3.; + Vector form_factor = Vector(2.0,2.0,1.0/0.3); + + for(unsigned res_idx=0; res_idx<natoms/3; res_idx++) { + + + const unsigned at_idx = 3*res_idx; + //center + for (unsigned j=0; j<3; j++) { + centers[res_idx] += w*positions[at_idx+j]; + } + + Vector3d a = delta(centers[res_idx],positions[at_idx]); + Vector3d b = delta(centers[res_idx],positions[at_idx+1]); + Vector3d d = crossProduct(a,b); + double ianorm = 1./a.modulo(); + double idnorm = 1./d.modulo(); + + // X vector: COM-C2 + pos[at_idx] = a*ianorm; + // Z versor: C2 x (COM-C4/C6) + pos[at_idx+2] = d*idnorm; + // Y versor: Z x Y + pos[at_idx+1] = crossProduct(pos[at_idx+2],pos[at_idx]); + + // Derivatives //////// + Tensor3d t1 = ianorm*(Tensor::identity()-extProduct(pos[at_idx],pos[at_idx])); + // dv1/dxa + deri[idx_deri] = (2./3. )*t1; + // dv1/dxb + deri[idx_deri+3] = -(1./3.)*t1; + // dv1/dxc + deri[idx_deri+6] = -(1./3.)*t1; + + Tensor dd_dxa = VcrossTensor(a,db_dxa) -VcrossTensor(b,da_dxa); + Tensor dd_dxb = VcrossTensor(a,db_dxb)-VcrossTensor(b,da_dxb); + Tensor dd_dxc = VcrossTensor(a,db_dxc)-VcrossTensor(b,da_dxc); + + // dv3/dxa + deri[idx_deri+2] = deriNorm(d,dd_dxa); + // dv3/dxb + deri[idx_deri+5] = deriNorm(d,dd_dxb); + // dv3/dxc + deri[idx_deri+8] = deriNorm(d,dd_dxc); + + // dv2/dxa = dv3/dxa cross v1 + v3 cross dv1/dxa + deri[idx_deri+1] = (VcrossTensor(deri[idx_deri+2],pos[at_idx]) + \ + VcrossTensor(pos[at_idx+2],deri[idx_deri])); + // dv2/dxb + deri[idx_deri+4] = (VcrossTensor(deri[idx_deri+5],pos[at_idx]) + \ + VcrossTensor(pos[at_idx+2],deri[idx_deri+3])); + // dv2/dxc + deri[idx_deri+7] = (VcrossTensor(deri[idx_deri+8],pos[at_idx]) + \ + VcrossTensor(pos[at_idx+2],deri[idx_deri+6])); + + idx_deri += 9; + // End derivatives /////// + + } + + + // Initialization (unnecessary?) + for (unsigned i1=0; i1<nresidues*nresidues; i1++) { + for (unsigned i2=0; i2<4; i2++) { + mat[i1][i2] = 0.0; + } + } + + double maxdist = cutoff/form_factor[0]; + double gamma = pi/cutoff; + unsigned idx; + unsigned idx1 = 0; + // Calculate mat + for (unsigned i=0; i<nresidues; i++) { + for (unsigned j=0; j<nresidues; j++) { + + // skip i==j + if(inPair(i,j) and i != j) { + //if(i!=j){ + + + // Calculate normal distance first + Vector diff = delta(centers[i],centers[j]); + double d1 = diff.modulo(); + //std::cout << inPair(i,j) << " " << i << " " << j << " "<< d1 <<"\n"; + //std::cout << inPair(i,j) << " " << i << " " << j << " "<< d1 <<"\n"; + if(d1<maxdist) { + + // calculate r_tilde_ij + Vector3d rtilde; + for (unsigned k=0; k<3; k++) { + for (unsigned l=0; l<3; l++) { + rtilde[l] += pos[3*i+l][k]*diff[k]*form_factor[l]; + } } - - } - - - double ERMSD::calculate(const std::vector<Vector> & positions,const Pbc& pbc,\ - std::vector<Vector> &derivatives, Tensor& virial) { - - - double ermsd=0.; - std::vector<Vector4d> mat; - mat.resize(nresidues*nresidues); - - std::vector<TensorGeneric<4,3> > Gderi; - Gderi.resize(natoms*natoms); - - calcMat(positions,pbc,mat,Gderi); - - unsigned idx1 = 0; - for(unsigned i=0;i<nresidues;i++){ - for(unsigned j=0;j<nresidues;j++){ - unsigned ii = i*nresidues + j; - - Vector4d dd = delta(reference_mat[ii],mat[ii]); - double val = dd.modulo2(); - //std::cout << "AAA " << i << " " << j << " " << ii << " "<< val << "\n"; - - if(val>0.0 && i!=j){ - - for(unsigned k=0;k<3;k++){ - idx1 = i*nresidues*6 + j*6 + k; - - derivatives[3*i+k] += matmul(dd,Gderi[idx1]); - derivatives[3*j+k] += matmul(dd,Gderi[idx1+3]); - } - ermsd += val; - } + double rtilde_norm = rtilde.modulo(); + + double irnorm = 1./rtilde_norm; + + // ellipsoidal cutoff + if(rtilde_norm < cutoff) { + idx = i*nresidues + j; + //std::cout << i << " " << j << " " << rtilde_norm << " " << idx <<"\n"; + + + // fill 4d matrix + double dummy = sin(gamma*rtilde_norm)/(rtilde_norm*gamma); + mat[idx][0] = dummy*rtilde[0]; + mat[idx][1] = dummy*rtilde[1]; + mat[idx][2] = dummy*rtilde[2]; + mat[idx][3] = (1.+ cos(gamma*rtilde_norm))/gamma; + + // Derivative (drtilde_dx) + std::vector<Tensor3d> drtilde_dx; + drtilde_dx.resize(6); + unsigned pos_idx = 3*i; + unsigned deri_idx = 9*i; + for (unsigned at=0; at<3; at++) { + for (unsigned l=0; l<3; l++) { + Vector3d rvec = form_factor[l]*((pos[pos_idx+l])/3.); + Vector3d vvec = form_factor[l]*(matmul(deri[deri_idx+3*at+l],diff)); + drtilde_dx[at].setRow(l,vvec-rvec); + drtilde_dx[at+3].setRow(l,rvec); + } + } + + //std::vector<TensorGeneric<4,3> > dG_dx; + //dG_dx.resize(6); + + double dummy1 = (cos(gamma*rtilde_norm) - dummy); + + idx1 = i*nresidues*6 + j*6; + + for (unsigned l=0; l<6; l++) { + //std::cout << i << " " << j << " " << idx1 << " " << idx1+l << "\n"; + + // components 1,2,3 + // sin(gamma*|rtilde|)/gamma*|rtilde|*d_rtilde + + // + ((d_rtilde*r_tilde/r_tilde^2) out r_tilde)* + // (cos(gamma*|rtilde| - sin(gamma*|rtilde|)/gamma*|rtilde|)) + Vector3d rdr = matmul(rtilde,drtilde_dx[l]); + Tensor tt = dummy*drtilde_dx[l] + (dummy1*irnorm*irnorm)*Tensor(rtilde,rdr); + for (unsigned m=0; m<3; m++) { + // Transpose here + //dG_dx[l].setRow(m,tt.getRow(m)); + Gderi[idx1+l].setRow(m,tt.getRow(m)); + } + // component 4 + // - sin(gamma*|rtilde|)/|rtilde|*(r_tilde*d_rtilde) + //dG_dx[l].setRow(3,-dummy*gamma*rdr); + Gderi[idx1+l].setRow(3,-dummy*gamma*rdr); + } + + + + } - } - - //std::cout << ermsd << " "; - //if(pairs.size()!=0) nresidues=pairs.size(); - //std::cout << ermsd << " " << nresidues; - ermsd = sqrt(ermsd/nresidues); - double iermsd = 1.0/(ermsd*nresidues); - for(unsigned i=0;i<natoms;++i){derivatives[i] *= iermsd;} - - return ermsd; + } + } + + } + } + +} + + +double ERMSD::calculate(const std::vector<Vector> & positions,const Pbc& pbc,\ + std::vector<Vector> &derivatives, Tensor& virial) { + + + double ermsd=0.; + std::vector<Vector4d> mat; + mat.resize(nresidues*nresidues); + + std::vector<TensorGeneric<4,3> > Gderi; + Gderi.resize(natoms*natoms); + + calcMat(positions,pbc,mat,Gderi); + + unsigned idx1 = 0; + for(unsigned i=0; i<nresidues; i++) { + for(unsigned j=0; j<nresidues; j++) { + unsigned ii = i*nresidues + j; + + Vector4d dd = delta(reference_mat[ii],mat[ii]); + double val = dd.modulo2(); + //std::cout << "AAA " << i << " " << j << " " << ii << " "<< val << "\n"; + + if(val>0.0 && i!=j) { + + for(unsigned k=0; k<3; k++) { + idx1 = i*nresidues*6 + j*6 + k; + + derivatives[3*i+k] += matmul(dd,Gderi[idx1]); + derivatives[3*j+k] += matmul(dd,Gderi[idx1+3]); + } + ermsd += val; + } + } + } + + //std::cout << ermsd << " "; + //if(pairs.size()!=0) nresidues=pairs.size(); + //std::cout << ermsd << " " << nresidues; + ermsd = sqrt(ermsd/nresidues); + double iermsd = 1.0/(ermsd*nresidues); + for(unsigned i=0; i<natoms; ++i) {derivatives[i] *= iermsd;} + + return ermsd; } - + } diff --git a/src/tools/ERMSD.h b/src/tools/ERMSD.h index cc4abcd38..f07d83711 100644 --- a/src/tools/ERMSD.h +++ b/src/tools/ERMSD.h @@ -30,42 +30,42 @@ #include <map> #include <utility> -namespace PLMD{ +namespace PLMD { class PDB; class Pbc; /// A class that implements ERMSD calculations class ERMSD { - //std::map< std::pair <unsigned,unsigned> , double> targets; - //unsigned natoms; - std::vector<Vector4d> reference_mat; - unsigned natoms; - unsigned nresidues; - std::vector<std::pair <unsigned,unsigned> > pairs; - double cutoff; - - public: + //std::map< std::pair <unsigned,unsigned> , double> targets; + //unsigned natoms; + std::vector<Vector4d> reference_mat; + unsigned natoms; + unsigned nresidues; + std::vector<std::pair <unsigned,unsigned> > pairs; + double cutoff; + +public: /// Constructor - ERMSD(): natoms(0),nresidues(0), cutoff(0.0) {} + ERMSD(): natoms(0),nresidues(0), cutoff(0.0) {} /// clear the structure - void clear(); + void clear(); - bool inPair(unsigned i, unsigned j); + bool inPair(unsigned i, unsigned j); /// set reference coordinates - void setReference(const std::vector<Vector> & reference, const std::vector<unsigned> & pairs_vec,double mycutoff=0.24); + void setReference(const std::vector<Vector> & reference, const std::vector<unsigned> & pairs_vec,double mycutoff=0.24); - void calcMat(const std::vector<Vector> & positions, const Pbc& pbc,std::vector<Vector4d> &mat,std::vector<TensorGeneric<4,3> > & Gderivatives); + void calcMat(const std::vector<Vector> & positions, const Pbc& pbc,std::vector<Vector4d> &mat,std::vector<TensorGeneric<4,3> > & Gderivatives); /// Compute ermsd ( no pbc ) // double calculate(const std::vector<Vector> & positions, // std::vector<Vector> &derivatives, Tensor& virial) const ; /// Compute ermsd ( with pbc ) - double calculate(const std::vector<Vector>& positions, const Pbc& pbc,std::vector<Vector> &derivatives, Tensor& virial); + double calculate(const std::vector<Vector>& positions, const Pbc& pbc,std::vector<Vector> &derivatives, Tensor& virial); }; - + } #endif diff --git a/src/tools/Exception.cpp b/src/tools/Exception.cpp index 06a989c82..223b4b141 100644 --- a/src/tools/Exception.cpp +++ b/src/tools/Exception.cpp @@ -21,7 +21,7 @@ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ #include "Exception.h" -#if defined(__PLUMED_HAS_EXECINFO) +#if defined(__PLUMED_HAS_EXECINFO) #include <execinfo.h> #endif @@ -29,12 +29,12 @@ #include <cstdlib> using namespace std; -namespace PLMD{ +namespace PLMD { -std::string Exception::format(const std::string&msg,const std::string&file,unsigned line,const std::string&function){ +std::string Exception::format(const std::string&msg,const std::string&file,unsigned line,const std::string&function) { std::string message; message="\n+++ Internal PLUMED error"; - if(file.length()>0){ + if(file.length()>0) { char cline[1000]; sprintf(cline,"%u",line); message += "\n+++ file "+file+", line "+cline; @@ -63,7 +63,7 @@ Exception::Exception(const std::string&msg,const std::string&file,unsigned line, abortIfExceptionsAreDisabled(); } -void Exception::abortIfExceptionsAreDisabled(){ +void Exception::abortIfExceptionsAreDisabled() { #if ! defined(__PLUMED_HAS_EXCEPTIONS) #ifdef __PLUMED_HAS_EXECINFO @@ -72,7 +72,7 @@ void Exception::abortIfExceptionsAreDisabled(){ int i, frames = backtrace(callstack, 128); char** strs = backtrace_symbols(callstack, frames); for (i = 0; i < frames; ++i) { - fprintf(stderr,"%s\n", strs[i]); + fprintf(stderr,"%s\n", strs[i]); } fprintf(stderr,"******** END STACK DUMP ********\n"); free(strs); diff --git a/src/tools/Exception.h b/src/tools/Exception.h index 9ed4f1afd..9e3c6dcf2 100644 --- a/src/tools/Exception.h +++ b/src/tools/Exception.h @@ -25,7 +25,7 @@ #include <string> #include <stdexcept> -namespace PLMD{ +namespace PLMD { /** \ingroup TOOLBOX @@ -45,7 +45,7 @@ or better add an error message to that if(something_bad) throw Exception("describe the error here); \endverbatim -Even better, you can use the predefined macros +Even better, you can use the predefined macros plumed_error(), plumed_assert(), plumed_merror() and plumed_massert(), which add information about the exact location of the error in the file (filename, line and, for g++, function name). Macros ending in "error" unconditionally throw @@ -108,9 +108,9 @@ public: /// With message plus file, line and function (meant to be used through a preprocessor macro) Exception(const std::string&,const std::string&,unsigned,const std::string&); /// Returns the error message - virtual const char* what() const throw(){return msg.c_str();} + virtual const char* what() const throw() {return msg.c_str();} /// Destructor should be defined and should not throw other exceptions - virtual ~Exception() throw(){} + virtual ~Exception() throw() {} }; // With GNU compiler, we can use __PRETTY_FUNCTION__ to get the function name @@ -132,7 +132,7 @@ public: #define plumed_massert(test,msg) if(!(test)) throw PLMD::Exception("assertion failed " #test ", " msg,__FILE__,__LINE__,__PRETTY_FUNCTION__) #ifdef NDEBUG -#define plumed_dbg_assert(test) +#define plumed_dbg_assert(test) #define plumed_dbg_massert(test,msg) #else /// \relates PLMD::Exception diff --git a/src/tools/FileBase.cpp b/src/tools/FileBase.cpp index fbcd97d86..cc38ceebf 100644 --- a/src/tools/FileBase.cpp +++ b/src/tools/FileBase.cpp @@ -37,62 +37,62 @@ #include <zlib.h> #endif -namespace PLMD{ +namespace PLMD { -FileBase& FileBase::link(FILE*fp){ +FileBase& FileBase::link(FILE*fp) { plumed_massert(!this->fp,"cannot link an already open file"); this->fp=fp; cloned=true; return *this; } -FileBase& FileBase::flush(){ +FileBase& FileBase::flush() { if(fp) fflush(fp); return *this; } -FileBase& FileBase::link(Communicator&comm){ +FileBase& FileBase::link(Communicator&comm) { plumed_massert(!fp,"cannot link an already open file"); this->comm=&comm; return *this; } -FileBase& FileBase::link(PlumedMain&plumed){ +FileBase& FileBase::link(PlumedMain&plumed) { plumed_massert(!fp,"cannot link an already open file"); this->plumed=&plumed; link(plumed.comm); return *this; } -FileBase& FileBase::link(Action&action){ +FileBase& FileBase::link(Action&action) { plumed_massert(!fp,"cannot link an already open file"); this->action=&action; link(action.plumed); return *this; } -bool FileBase::FileExist(const std::string& path){ +bool FileBase::FileExist(const std::string& path) { bool do_exist=false; this->path=appendSuffix(path,getSuffix()); mode="r"; FILE *ff=std::fopen(const_cast<char*>(this->path.c_str()),"r"); - if(!ff){ + if(!ff) { this->path=path; ff=std::fopen(const_cast<char*>(this->path.c_str()),"r"); mode="r"; } if(ff) {do_exist=true; fclose(ff);} if(comm) comm->Barrier(); - return do_exist; + return do_exist; } -bool FileBase::isOpen(){ +bool FileBase::isOpen() { bool isopen=false; if(fp) isopen=true; - return isopen; + return isopen; } -void FileBase::close(){ +void FileBase::close() { plumed_assert(!cloned); eof=false; err=false; @@ -127,11 +127,11 @@ FileBase::~FileBase() #endif } -FileBase::operator bool()const{ +FileBase::operator bool()const { return !eof; } -std::string FileBase::appendSuffix(const std::string&path,const std::string&suffix){ +std::string FileBase::appendSuffix(const std::string&path,const std::string&suffix) { if(path=="/dev/null") return path; // do not append a suffix to /dev/null std::string ret=path; std::string ext=Tools::extension(path); @@ -144,7 +144,7 @@ std::string FileBase::appendSuffix(const std::string&path,const std::string&suff // Removing this line, any extension recognized by Tools::extension() would be considered // if(ext!="gz" && ext!="xtc" && ext!="trr") ext=""; - if(ext.length()>0){ + if(ext.length()>0) { int l=path.length()-(ext.length()+1); plumed_assert(l>=0); ret=ret.substr(0,l); @@ -154,13 +154,13 @@ std::string FileBase::appendSuffix(const std::string&path,const std::string&suff return ret; } -FileBase& FileBase::enforceSuffix(const std::string&suffix){ +FileBase& FileBase::enforceSuffix(const std::string&suffix) { enforcedSuffix_=true; enforcedSuffix=suffix; return *this; } -std::string FileBase::getSuffix()const{ +std::string FileBase::getSuffix()const { if(enforcedSuffix_) return enforcedSuffix; if(plumed) return plumed->getSuffix(); return ""; diff --git a/src/tools/FileBase.h b/src/tools/FileBase.h index f9715511e..e205aa2cb 100644 --- a/src/tools/FileBase.h +++ b/src/tools/FileBase.h @@ -24,7 +24,7 @@ #include <string> -namespace PLMD{ +namespace PLMD { class Communicator; class PlumedMain; @@ -36,7 +36,7 @@ Base class for dealing with files. This class just provides things which are common among OFile and IFile */ -class FileBase{ +class FileBase { /// Copy constructor is disabled (private and unimplemented) explicit FileBase(const FileBase&); /// Assignment operator is disabled (private and unimplemented) @@ -44,13 +44,13 @@ class FileBase{ protected: /// Internal tool. /// Base for IFile::Field and OFile::Field - class FieldBase{ + class FieldBase { // everything is public to simplify usage public: std::string name; std::string value; bool constant; - FieldBase(): constant(false){} + FieldBase(): constant(false) {} }; /// file pointer @@ -113,7 +113,7 @@ public: /// Check for error/eof. operator bool () const; /// Set heavyFlush flag - void setHeavyFlush(){ heavyFlush=true;} + void setHeavyFlush() { heavyFlush=true;} /// Opens the file virtual FileBase& open(const std::string&name)=0; /// Check if the file exists @@ -129,12 +129,12 @@ public: }; inline -std::string FileBase::getPath()const{ +std::string FileBase::getPath()const { return path; } inline -std::string FileBase::getMode()const{ +std::string FileBase::getMode()const { return mode; } diff --git a/src/tools/Grid.cpp b/src/tools/Grid.cpp index 72533567a..472ae2936 100644 --- a/src/tools/Grid.cpp +++ b/src/tools/Grid.cpp @@ -37,913 +37,913 @@ #include <cfloat> using namespace std; -namespace PLMD{ +namespace PLMD { -Grid::Grid(const std::string& funcl, const std::vector<Value*> & args, const vector<std::string> & gmin, - const vector<std::string> & gmax, const vector<unsigned> & nbin, bool dospline, bool usederiv, bool doclear){ +Grid::Grid(const std::string& funcl, const std::vector<Value*> & args, const vector<std::string> & gmin, + const vector<std::string> & gmax, const vector<unsigned> & nbin, bool dospline, bool usederiv, bool doclear) { // various checks - plumed_massert(args.size()==gmin.size(),"grid min dimensions in input do not match number of arguments"); - plumed_massert(args.size()==nbin.size(),"number of bins on input do not match number of arguments"); - plumed_massert(args.size()==gmax.size(),"grid max dimensions in input do not match number of arguments"); - unsigned dim=gmax.size(); - std::vector<std::string> names; - std::vector<bool> isperiodic; - std::vector<string> pmin,pmax; - names.resize( dim ); - isperiodic.resize( dim ); - pmin.resize( dim ); - pmax.resize( dim ); - for(unsigned int i=0;i<dim;++i){ - names[i]=args[i]->getName(); - if( args[i]->isPeriodic() ){ - isperiodic[i]=true; + plumed_massert(args.size()==gmin.size(),"grid min dimensions in input do not match number of arguments"); + plumed_massert(args.size()==nbin.size(),"number of bins on input do not match number of arguments"); + plumed_massert(args.size()==gmax.size(),"grid max dimensions in input do not match number of arguments"); + unsigned dim=gmax.size(); + std::vector<std::string> names; + std::vector<bool> isperiodic; + std::vector<string> pmin,pmax; + names.resize( dim ); + isperiodic.resize( dim ); + pmin.resize( dim ); + pmax.resize( dim ); + for(unsigned int i=0; i<dim; ++i) { + names[i]=args[i]->getName(); + if( args[i]->isPeriodic() ) { + isperiodic[i]=true; args[i]->getDomain( pmin[i], pmax[i] ); - } else { + } else { isperiodic[i]=false; pmin[i]="0."; pmax[i]="0."; + } } - } - // this is a value-independent initializator - Init(funcl,names,gmin,gmax,nbin,dospline,usederiv,doclear,isperiodic,pmin,pmax); +// this is a value-independent initializator + Init(funcl,names,gmin,gmax,nbin,dospline,usederiv,doclear,isperiodic,pmin,pmax); } -Grid::Grid(const std::string& funcl, const std::vector<string> &names, const std::vector<std::string> & gmin, - const vector<std::string> & gmax, const std::vector<unsigned> & nbin, bool dospline, bool usederiv, bool doclear, const std::vector<bool> &isperiodic, const std::vector<std::string> &pmin, const std::vector<std::string> &pmax ){ - // this calls the initializator - Init(funcl,names,gmin,gmax,nbin,dospline,usederiv,doclear,isperiodic,pmin,pmax); +Grid::Grid(const std::string& funcl, const std::vector<string> &names, const std::vector<std::string> & gmin, + const vector<std::string> & gmax, const std::vector<unsigned> & nbin, bool dospline, bool usederiv, bool doclear, const std::vector<bool> &isperiodic, const std::vector<std::string> &pmin, const std::vector<std::string> &pmax ) { +// this calls the initializator + Init(funcl,names,gmin,gmax,nbin,dospline,usederiv,doclear,isperiodic,pmin,pmax); } -void Grid::Init(const std::string& funcl, const std::vector<std::string> &names, const vector<std::string> & gmin, - const std::vector<std::string> & gmax, const std::vector<unsigned> & nbin, bool dospline, bool usederiv, bool doclear, - const std::vector<bool> &isperiodic, const std::vector<std::string> &pmin, const std::vector<std::string> &pmax ){ - contour_location=0.0; fmt_="%14.9f"; +void Grid::Init(const std::string& funcl, const std::vector<std::string> &names, const vector<std::string> & gmin, + const std::vector<std::string> & gmax, const std::vector<unsigned> & nbin, bool dospline, bool usederiv, bool doclear, + const std::vector<bool> &isperiodic, const std::vector<std::string> &pmin, const std::vector<std::string> &pmax ) { + contour_location=0.0; fmt_="%14.9f"; // various checks - plumed_massert(names.size()==gmin.size(),"grid dimensions in input do not match number of arguments"); - plumed_massert(names.size()==nbin.size(),"grid dimensions in input do not match number of arguments"); - plumed_massert(names.size()==gmax.size(),"grid dimensions in input do not match number of arguments"); - dimension_=gmax.size(); - str_min_=gmin; str_max_=gmax; - argnames.resize( dimension_ ); - min_.resize( dimension_ ); - max_.resize( dimension_ ); - pbc_.resize( dimension_ ); - for(unsigned int i=0;i<dimension_;++i){ - argnames[i]=names[i]; - if( isperiodic[i] ){ - pbc_[i]=true; + plumed_massert(names.size()==gmin.size(),"grid dimensions in input do not match number of arguments"); + plumed_massert(names.size()==nbin.size(),"grid dimensions in input do not match number of arguments"); + plumed_massert(names.size()==gmax.size(),"grid dimensions in input do not match number of arguments"); + dimension_=gmax.size(); + str_min_=gmin; str_max_=gmax; + argnames.resize( dimension_ ); + min_.resize( dimension_ ); + max_.resize( dimension_ ); + pbc_.resize( dimension_ ); + for(unsigned int i=0; i<dimension_; ++i) { + argnames[i]=names[i]; + if( isperiodic[i] ) { + pbc_[i]=true; str_min_[i]=pmin[i]; str_max_[i]=pmax[i]; - } else { + } else { pbc_[i]=false; + } + Tools::convert(str_min_[i],min_[i]); + Tools::convert(str_max_[i],max_[i]); + funcname=funcl; + plumed_massert(max_[i]>min_[i],"maximum in grid must be larger than minimum"); + plumed_massert(nbin[i]>0,"number of grid points must be greater than zero"); + } + nbin_=nbin; + dospline_=dospline; + usederiv_=usederiv; + if(dospline_) plumed_assert(dospline_==usederiv_); + maxsize_=1; + for(unsigned int i=0; i<dimension_; ++i) { + dx_.push_back( (max_[i]-min_[i])/static_cast<double>( nbin_[i] ) ); + if( !pbc_[i] ) { max_[i] += dx_[i]; nbin_[i] += 1; } + maxsize_*=nbin_[i]; + } + if(doclear) clear(); +} + +void Grid::clear() { + grid_.resize(maxsize_); + if(usederiv_) der_.resize(maxsize_); + for(index_t i=0; i<maxsize_; ++i) { + grid_[i]=0.0; + if(usederiv_) { + (der_[i]).resize(dimension_); + for(unsigned int j=0; j<dimension_; ++j) der_[i][j]=0.0; + } } - Tools::convert(str_min_[i],min_[i]); - Tools::convert(str_max_[i],max_[i]); - funcname=funcl; - plumed_massert(max_[i]>min_[i],"maximum in grid must be larger than minimum"); - plumed_massert(nbin[i]>0,"number of grid points must be greater than zero"); - } - nbin_=nbin; - dospline_=dospline; - usederiv_=usederiv; - if(dospline_) plumed_assert(dospline_==usederiv_); - maxsize_=1; - for(unsigned int i=0;i<dimension_;++i){ - dx_.push_back( (max_[i]-min_[i])/static_cast<double>( nbin_[i] ) ); - if( !pbc_[i] ){ max_[i] += dx_[i]; nbin_[i] += 1; } - maxsize_*=nbin_[i]; - } - if(doclear) clear(); -} - -void Grid::clear(){ - grid_.resize(maxsize_); - if(usederiv_) der_.resize(maxsize_); - for(index_t i=0;i<maxsize_;++i){ - grid_[i]=0.0; - if(usederiv_){ - (der_[i]).resize(dimension_); - for(unsigned int j=0;j<dimension_;++j) der_[i][j]=0.0; - } - } } vector<std::string> Grid::getMin() const { - return str_min_; + return str_min_; } vector<std::string> Grid::getMax() const { - return str_max_; + return str_max_; } vector<double> Grid::getDx() const { - return dx_; + return dx_; } double Grid::getBinVolume() const { - double vol=1.; - for(unsigned i=0;i<dx_.size();++i) vol*=dx_[i]; - return vol; + double vol=1.; + for(unsigned i=0; i<dx_.size(); ++i) vol*=dx_[i]; + return vol; } vector<bool> Grid::getIsPeriodic() const { - return pbc_; + return pbc_; } vector<unsigned> Grid::getNbin() const { - return nbin_; + return nbin_; } vector<string> Grid::getArgNames() const { - return argnames; + return argnames; } Grid::index_t Grid::getSize() const { - return maxsize_; + return maxsize_; } unsigned Grid::getDimension() const { - return dimension_; + return dimension_; } // we are flattening arrays using a column-major order Grid::index_t Grid::getIndex(const vector<unsigned> & indices) const { - plumed_dbg_assert(indices.size()==dimension_); - for(unsigned int i=0;i<dimension_;i++) - if(indices[i]>=nbin_[i]) { - std::string is; - Tools::convert(i,is); - std::string msg="ERROR: the system is looking for a value outside the grid along the " + is + " ("+getArgNames()[i]+")"; - plumed_merror(msg+" index!"); + plumed_dbg_assert(indices.size()==dimension_); + for(unsigned int i=0; i<dimension_; i++) + if(indices[i]>=nbin_[i]) { + std::string is; + Tools::convert(i,is); + std::string msg="ERROR: the system is looking for a value outside the grid along the " + is + " ("+getArgNames()[i]+")"; + plumed_merror(msg+" index!"); + } + index_t index=indices[dimension_-1]; + for(unsigned int i=dimension_-1; i>0; --i) { + index=index*nbin_[i-1]+indices[i-1]; } - index_t index=indices[dimension_-1]; - for(unsigned int i=dimension_-1;i>0;--i){ - index=index*nbin_[i-1]+indices[i-1]; - } - return index; + return index; } Grid::index_t Grid::getIndex(const vector<double> & x) const { - plumed_dbg_assert(x.size()==dimension_); - return getIndex(getIndices(x)); + plumed_dbg_assert(x.size()==dimension_); + return getIndex(getIndices(x)); } // we are flattening arrays using a column-major order vector<unsigned> Grid::getIndices(index_t index) const { - vector<unsigned> indices(dimension_); - index_t kk=index; - indices[0]=(index%nbin_[0]); - for(unsigned int i=1;i<dimension_-1;++i){ - kk=(kk-indices[i-1])/nbin_[i-1]; - indices[i]=(kk%nbin_[i]); - } - if(dimension_>=2){ - indices[dimension_-1]=((kk-indices[dimension_-2])/nbin_[dimension_-2]); - } - return indices; + vector<unsigned> indices(dimension_); + index_t kk=index; + indices[0]=(index%nbin_[0]); + for(unsigned int i=1; i<dimension_-1; ++i) { + kk=(kk-indices[i-1])/nbin_[i-1]; + indices[i]=(kk%nbin_[i]); + } + if(dimension_>=2) { + indices[dimension_-1]=((kk-indices[dimension_-2])/nbin_[dimension_-2]); + } + return indices; } vector<unsigned> Grid::getIndices(const vector<double> & x) const { - plumed_dbg_assert(x.size()==dimension_); - vector<unsigned> indices; - for(unsigned int i=0;i<dimension_;++i){ - indices.push_back(unsigned(floor((x[i]-min_[i])/dx_[i]))); - } - return indices; + plumed_dbg_assert(x.size()==dimension_); + vector<unsigned> indices; + for(unsigned int i=0; i<dimension_; ++i) { + indices.push_back(unsigned(floor((x[i]-min_[i])/dx_[i]))); + } + return indices; } vector<double> Grid::getPoint(const vector<unsigned> & indices) const { - plumed_dbg_assert(indices.size()==dimension_); - vector<double> x; - for(unsigned int i=0;i<dimension_;++i){ - x.push_back(min_[i]+(double)(indices[i])*dx_[i]); - } - return x; + plumed_dbg_assert(indices.size()==dimension_); + vector<double> x; + for(unsigned int i=0; i<dimension_; ++i) { + x.push_back(min_[i]+(double)(indices[i])*dx_[i]); + } + return x; } vector<double> Grid::getPoint(index_t index) const { - plumed_dbg_assert(index<maxsize_); - return getPoint(getIndices(index)); + plumed_dbg_assert(index<maxsize_); + return getPoint(getIndices(index)); } vector<double> Grid::getPoint(const vector<double> & x) const { - plumed_dbg_assert(x.size()==dimension_); - return getPoint(getIndices(x)); + plumed_dbg_assert(x.size()==dimension_); + return getPoint(getIndices(x)); } -void Grid::getPoint(index_t index,std::vector<double> & point) const{ - plumed_dbg_assert(index<maxsize_); - getPoint(getIndices(index),point); +void Grid::getPoint(index_t index,std::vector<double> & point) const { + plumed_dbg_assert(index<maxsize_); + getPoint(getIndices(index),point); } -void Grid::getPoint(const std::vector<unsigned> & indices,std::vector<double> & point) const{ - plumed_dbg_assert(indices.size()==dimension_); - plumed_dbg_assert(point.size()==dimension_); - for(unsigned int i=0;i<dimension_;++i){ - point[i]=(min_[i]+(double)(indices[i])*dx_[i]); - } +void Grid::getPoint(const std::vector<unsigned> & indices,std::vector<double> & point) const { + plumed_dbg_assert(indices.size()==dimension_); + plumed_dbg_assert(point.size()==dimension_); + for(unsigned int i=0; i<dimension_; ++i) { + point[i]=(min_[i]+(double)(indices[i])*dx_[i]); + } } -void Grid::getPoint(const std::vector<double> & x,std::vector<double> & point) const{ - plumed_dbg_assert(x.size()==dimension_); - getPoint(getIndices(x),point); +void Grid::getPoint(const std::vector<double> & x,std::vector<double> & point) const { + plumed_dbg_assert(x.size()==dimension_); + getPoint(getIndices(x),point); } vector<Grid::index_t> Grid::getNeighbors - (const vector<unsigned> &indices,const vector<unsigned> &nneigh)const{ - plumed_dbg_assert(indices.size()==dimension_ && nneigh.size()==dimension_); - - vector<index_t> neighbors; - vector<unsigned> small_bin(dimension_); - - unsigned small_nbin=1; - for(unsigned j=0;j<dimension_;++j){ - small_bin[j]=(2*nneigh[j]+1); - small_nbin*=small_bin[j]; - } - - vector<unsigned> small_indices(dimension_); - vector<unsigned> tmp_indices; - for(unsigned index=0;index<small_nbin;++index){ - tmp_indices.resize(dimension_); - unsigned kk=index; - small_indices[0]=(index%small_bin[0]); - for(unsigned i=1;i<dimension_-1;++i){ - kk=(kk-small_indices[i-1])/small_bin[i-1]; - small_indices[i]=(kk%small_bin[i]); - } - if(dimension_>=2){ - small_indices[dimension_-1]=((kk-small_indices[dimension_-2])/small_bin[dimension_-2]); - } - unsigned ll=0; - for(unsigned i=0;i<dimension_;++i){ - int i0=small_indices[i]-nneigh[i]+indices[i]; - if(!pbc_[i] && i0<0) continue; - if(!pbc_[i] && i0>=nbin_[i]) continue; - if( pbc_[i] && i0<0) i0=nbin_[i]-(-i0)%nbin_[i]; - if( pbc_[i] && i0>=nbin_[i]) i0%=nbin_[i]; - tmp_indices[ll]=((unsigned)i0); - ll++; - } - tmp_indices.resize(ll); - if(tmp_indices.size()==dimension_){neighbors.push_back(getIndex(tmp_indices));} - } - return neighbors; -} - +(const vector<unsigned> &indices,const vector<unsigned> &nneigh)const { + plumed_dbg_assert(indices.size()==dimension_ && nneigh.size()==dimension_); + + vector<index_t> neighbors; + vector<unsigned> small_bin(dimension_); + + unsigned small_nbin=1; + for(unsigned j=0; j<dimension_; ++j) { + small_bin[j]=(2*nneigh[j]+1); + small_nbin*=small_bin[j]; + } + + vector<unsigned> small_indices(dimension_); + vector<unsigned> tmp_indices; + for(unsigned index=0; index<small_nbin; ++index) { + tmp_indices.resize(dimension_); + unsigned kk=index; + small_indices[0]=(index%small_bin[0]); + for(unsigned i=1; i<dimension_-1; ++i) { + kk=(kk-small_indices[i-1])/small_bin[i-1]; + small_indices[i]=(kk%small_bin[i]); + } + if(dimension_>=2) { + small_indices[dimension_-1]=((kk-small_indices[dimension_-2])/small_bin[dimension_-2]); + } + unsigned ll=0; + for(unsigned i=0; i<dimension_; ++i) { + int i0=small_indices[i]-nneigh[i]+indices[i]; + if(!pbc_[i] && i0<0) continue; + if(!pbc_[i] && i0>=nbin_[i]) continue; + if( pbc_[i] && i0<0) i0=nbin_[i]-(-i0)%nbin_[i]; + if( pbc_[i] && i0>=nbin_[i]) i0%=nbin_[i]; + tmp_indices[ll]=((unsigned)i0); + ll++; + } + tmp_indices.resize(ll); + if(tmp_indices.size()==dimension_) {neighbors.push_back(getIndex(tmp_indices));} + } + return neighbors; +} + vector<Grid::index_t> Grid::getNeighbors - (const vector<double> & x,const vector<unsigned> & nneigh)const{ - plumed_dbg_assert(x.size()==dimension_ && nneigh.size()==dimension_); - return getNeighbors(getIndices(x),nneigh); +(const vector<double> & x,const vector<unsigned> & nneigh)const { + plumed_dbg_assert(x.size()==dimension_ && nneigh.size()==dimension_); + return getNeighbors(getIndices(x),nneigh); } vector<Grid::index_t> Grid::getNeighbors - (index_t index,const vector<unsigned> & nneigh)const{ - plumed_dbg_assert(index<maxsize_ && nneigh.size()==dimension_); - return getNeighbors(getIndices(index),nneigh); -} - -vector<Grid::index_t> Grid::getSplineNeighbors(const vector<unsigned> & indices)const{ - plumed_dbg_assert(indices.size()==dimension_); - vector<index_t> neighbors; - unsigned nneigh=unsigned(pow(2.0,int(dimension_))); - - for(unsigned int i=0;i<nneigh;++i){ - unsigned tmp=i; - vector<unsigned> nindices; - for(unsigned int j=0;j<dimension_;++j){ - unsigned i0=tmp%2+indices[j]; - tmp/=2; - if(!pbc_[j] && i0==nbin_[j]) continue; - if( pbc_[j] && i0==nbin_[j]) i0=0; - nindices.push_back(i0); - } - if(nindices.size()==dimension_) neighbors.push_back(getIndex(nindices)); - } - return neighbors; -} - -void Grid::addKernel( const KernelFunctions& kernel ){ +(index_t index,const vector<unsigned> & nneigh)const { + plumed_dbg_assert(index<maxsize_ && nneigh.size()==dimension_); + return getNeighbors(getIndices(index),nneigh); +} + +vector<Grid::index_t> Grid::getSplineNeighbors(const vector<unsigned> & indices)const { + plumed_dbg_assert(indices.size()==dimension_); + vector<index_t> neighbors; + unsigned nneigh=unsigned(pow(2.0,int(dimension_))); + + for(unsigned int i=0; i<nneigh; ++i) { + unsigned tmp=i; + vector<unsigned> nindices; + for(unsigned int j=0; j<dimension_; ++j) { + unsigned i0=tmp%2+indices[j]; + tmp/=2; + if(!pbc_[j] && i0==nbin_[j]) continue; + if( pbc_[j] && i0==nbin_[j]) i0=0; + nindices.push_back(i0); + } + if(nindices.size()==dimension_) neighbors.push_back(getIndex(nindices)); + } + return neighbors; +} + +void Grid::addKernel( const KernelFunctions& kernel ) { plumed_dbg_assert( kernel.ndim()==dimension_ ); std::vector<unsigned> nneighb=kernel.getSupport( dx_ ); std::vector<index_t> neighbors=getNeighbors( kernel.getCenter(), nneighb ); std::vector<double> xx( dimension_ ); std::vector<Value*> vv( dimension_ ); std::string str_min, str_max; - for(unsigned i=0;i<dimension_;++i){ - vv[i]=new Value(); - if( pbc_[i] ){ - Tools::convert(min_[i],str_min); - Tools::convert(max_[i],str_max); - vv[i]->setDomain( str_min, str_max ); - } else { - vv[i]->setNotPeriodic(); - } + for(unsigned i=0; i<dimension_; ++i) { + vv[i]=new Value(); + if( pbc_[i] ) { + Tools::convert(min_[i],str_min); + Tools::convert(max_[i],str_max); + vv[i]->setDomain( str_min, str_max ); + } else { + vv[i]->setNotPeriodic(); + } } std::vector<double> der( dimension_ ); - for(unsigned i=0;i<neighbors.size();++i){ - index_t ineigh=neighbors[i]; - getPoint( ineigh, xx ); - for(unsigned j=0;j<dimension_;++j) vv[j]->set(xx[j]); - double newval = kernel.evaluate( vv, der, usederiv_ ); - if( usederiv_ ) addValueAndDerivatives( ineigh, newval, der ); - else addValue( ineigh, newval ); + for(unsigned i=0; i<neighbors.size(); ++i) { + index_t ineigh=neighbors[i]; + getPoint( ineigh, xx ); + for(unsigned j=0; j<dimension_; ++j) vv[j]->set(xx[j]); + double newval = kernel.evaluate( vv, der, usederiv_ ); + if( usederiv_ ) addValueAndDerivatives( ineigh, newval, der ); + else addValue( ineigh, newval ); } - for(unsigned i=0;i<dimension_;++i) delete vv[i]; + for(unsigned i=0; i<dimension_; ++i) delete vv[i]; } double Grid::getValue(index_t index) const { - plumed_dbg_assert(index<maxsize_); - return grid_[index]; + plumed_dbg_assert(index<maxsize_); + return grid_[index]; } double Grid::getMinValue() const { - double minval; - minval=DBL_MAX; - for(index_t i=0;i<grid_.size();++i){ - if(grid_[i]<minval)minval=grid_[i]; - } - return minval; + double minval; + minval=DBL_MAX; + for(index_t i=0; i<grid_.size(); ++i) { + if(grid_[i]<minval)minval=grid_[i]; + } + return minval; } double Grid::getMaxValue() const { - double maxval; - maxval=DBL_MIN; - for(index_t i=0;i<grid_.size();++i){ - if(grid_[i]>maxval)maxval=grid_[i]; - } - return maxval; + double maxval; + maxval=DBL_MIN; + for(index_t i=0; i<grid_.size(); ++i) { + if(grid_[i]>maxval)maxval=grid_[i]; + } + return maxval; } double Grid::getValue(const vector<unsigned> & indices) const { - return getValue(getIndex(indices)); + return getValue(getIndex(indices)); } double Grid::getValue(const vector<double> & x) const { - if(!dospline_){ - return getValue(getIndex(x)); - } else { - vector<double> der(dimension_); - return getValueAndDerivatives(x,der); - } + if(!dospline_) { + return getValue(getIndex(x)); + } else { + vector<double> der(dimension_); + return getValueAndDerivatives(x,der); + } } double Grid::getValueAndDerivatives - (index_t index, vector<double>& der) const{ - plumed_dbg_assert(index<maxsize_ && usederiv_ && der.size()==dimension_); - der=der_[index]; - return grid_[index]; +(index_t index, vector<double>& der) const { + plumed_dbg_assert(index<maxsize_ && usederiv_ && der.size()==dimension_); + der=der_[index]; + return grid_[index]; } double Grid::getValueAndDerivatives - (const vector<unsigned> & indices, vector<double>& der) const{ - return getValueAndDerivatives(getIndex(indices),der); +(const vector<unsigned> & indices, vector<double>& der) const { + return getValueAndDerivatives(getIndex(indices),der); } double Grid::getValueAndDerivatives (const vector<double> & x, vector<double>& der) const { - plumed_dbg_assert(der.size()==dimension_ && usederiv_); - - if(dospline_){ - double X,X2,X3,value; - vector<double> fd(dimension_); - vector<double> C(dimension_); - vector<double> D(dimension_); - vector<double> dder(dimension_); + plumed_dbg_assert(der.size()==dimension_ && usederiv_); + + if(dospline_) { + double X,X2,X3,value; + vector<double> fd(dimension_); + vector<double> C(dimension_); + vector<double> D(dimension_); + vector<double> dder(dimension_); // reset - value=0.0; - for(unsigned int i=0;i<dimension_;++i) der[i]=0.0; + value=0.0; + for(unsigned int i=0; i<dimension_; ++i) der[i]=0.0; - vector<unsigned> indices=getIndices(x); - vector<index_t> neigh=getSplineNeighbors(indices); - vector<double> xfloor=getPoint(x); + vector<unsigned> indices=getIndices(x); + vector<index_t> neigh=getSplineNeighbors(indices); + vector<double> xfloor=getPoint(x); // loop over neighbors - for(unsigned int ipoint=0;ipoint<neigh.size();++ipoint){ - double grid=getValueAndDerivatives(neigh[ipoint],dder); - vector<unsigned> nindices=getIndices(neigh[ipoint]); - double ff=1.0; - - for(unsigned j=0;j<dimension_;++j){ - int x0=1; - if(nindices[j]==indices[j]) x0=0; - double dx=getDx()[j]; - X=fabs((x[j]-xfloor[j])/dx-(double)x0); - X2=X*X; - X3=X2*X; - double yy; - if(fabs(grid)<0.0000001) yy=0.0; - else yy=-dder[j]/grid; - C[j]=(1.0-3.0*X2+2.0*X3) - (x0?-1.0:1.0)*yy*(X-2.0*X2+X3)*dx; - D[j]=( -6.0*X +6.0*X2) - (x0?-1.0:1.0)*yy*(1.0-4.0*X +3.0*X2)*dx; - D[j]*=(x0?-1.0:1.0)/dx; - ff*=C[j]; - } - for(unsigned j=0;j<dimension_;++j){ - fd[j]=D[j]; - for(unsigned i=0;i<dimension_;++i) if(i!=j) fd[j]*=C[i]; - } - value+=grid*ff; - for(unsigned j=0;j<dimension_;++j) der[j]+=grid*fd[j]; + for(unsigned int ipoint=0; ipoint<neigh.size(); ++ipoint) { + double grid=getValueAndDerivatives(neigh[ipoint],dder); + vector<unsigned> nindices=getIndices(neigh[ipoint]); + double ff=1.0; + + for(unsigned j=0; j<dimension_; ++j) { + int x0=1; + if(nindices[j]==indices[j]) x0=0; + double dx=getDx()[j]; + X=fabs((x[j]-xfloor[j])/dx-(double)x0); + X2=X*X; + X3=X2*X; + double yy; + if(fabs(grid)<0.0000001) yy=0.0; + else yy=-dder[j]/grid; + C[j]=(1.0-3.0*X2+2.0*X3) - (x0?-1.0:1.0)*yy*(X-2.0*X2+X3)*dx; + D[j]=( -6.0*X +6.0*X2) - (x0?-1.0:1.0)*yy*(1.0-4.0*X +3.0*X2)*dx; + D[j]*=(x0?-1.0:1.0)/dx; + ff*=C[j]; + } + for(unsigned j=0; j<dimension_; ++j) { + fd[j]=D[j]; + for(unsigned i=0; i<dimension_; ++i) if(i!=j) fd[j]*=C[i]; + } + value+=grid*ff; + for(unsigned j=0; j<dimension_; ++j) der[j]+=grid*fd[j]; + } + return value; + } else { + return getValueAndDerivatives(getIndex(x),der); } - return value; - }else{ - return getValueAndDerivatives(getIndex(x),der); - } } -void Grid::setValue(index_t index, double value){ - plumed_dbg_assert(index<maxsize_ && !usederiv_); - grid_[index]=value; +void Grid::setValue(index_t index, double value) { + plumed_dbg_assert(index<maxsize_ && !usederiv_); + grid_[index]=value; } -void Grid::setValue(const vector<unsigned> & indices, double value){ - setValue(getIndex(indices),value); +void Grid::setValue(const vector<unsigned> & indices, double value) { + setValue(getIndex(indices),value); } void Grid::setValueAndDerivatives - (index_t index, double value, vector<double>& der){ - plumed_dbg_assert(index<maxsize_ && usederiv_ && der.size()==dimension_); - grid_[index]=value; - der_[index]=der; +(index_t index, double value, vector<double>& der) { + plumed_dbg_assert(index<maxsize_ && usederiv_ && der.size()==dimension_); + grid_[index]=value; + der_[index]=der; } void Grid::setValueAndDerivatives - (const vector<unsigned> & indices, double value, vector<double>& der){ - setValueAndDerivatives(getIndex(indices),value,der); +(const vector<unsigned> & indices, double value, vector<double>& der) { + setValueAndDerivatives(getIndex(indices),value,der); } -void Grid::addValue(index_t index, double value){ - plumed_dbg_assert(index<maxsize_ && !usederiv_); - grid_[index]+=value; +void Grid::addValue(index_t index, double value) { + plumed_dbg_assert(index<maxsize_ && !usederiv_); + grid_[index]+=value; } -void Grid::addValue(const vector<unsigned> & indices, double value){ - addValue(getIndex(indices),value); +void Grid::addValue(const vector<unsigned> & indices, double value) { + addValue(getIndex(indices),value); } void Grid::addValueAndDerivatives - (index_t index, double value, vector<double>& der){ - plumed_dbg_assert(index<maxsize_ && usederiv_ && der.size()==dimension_); - grid_[index]+=value; - for(unsigned int i=0;i<dimension_;++i) der_[index][i]+=der[i]; +(index_t index, double value, vector<double>& der) { + plumed_dbg_assert(index<maxsize_ && usederiv_ && der.size()==dimension_); + grid_[index]+=value; + for(unsigned int i=0; i<dimension_; ++i) der_[index][i]+=der[i]; } void Grid::addValueAndDerivatives - (const vector<unsigned> & indices, double value, vector<double>& der){ - addValueAndDerivatives(getIndex(indices),value,der); +(const vector<unsigned> & indices, double value, vector<double>& der) { + addValueAndDerivatives(getIndex(indices),value,der); } -void Grid::scaleAllValuesAndDerivatives( const double& scalef ){ - if(usederiv_){ - for(index_t i=0;i<grid_.size();++i){ - grid_[i]*=scalef; - for(unsigned j=0;j<dimension_;++j) der_[i][j]*=scalef; - } +void Grid::scaleAllValuesAndDerivatives( const double& scalef ) { + if(usederiv_) { + for(index_t i=0; i<grid_.size(); ++i) { + grid_[i]*=scalef; + for(unsigned j=0; j<dimension_; ++j) der_[i][j]*=scalef; + } } else { - for(index_t i=0;i<grid_.size();++i) grid_[i]*=scalef; + for(index_t i=0; i<grid_.size(); ++i) grid_[i]*=scalef; } } -void Grid::logAllValuesAndDerivatives( const double& scalef ){ - if(usederiv_){ - for(index_t i=0;i<grid_.size();++i){ - grid_[i] = scalef*log(grid_[i]); - for(unsigned j=0;j<dimension_;++j) der_[i][j] = scalef/der_[i][j]; - } +void Grid::logAllValuesAndDerivatives( const double& scalef ) { + if(usederiv_) { + for(index_t i=0; i<grid_.size(); ++i) { + grid_[i] = scalef*log(grid_[i]); + for(unsigned j=0; j<dimension_; ++j) der_[i][j] = scalef/der_[i][j]; + } } else { - for(index_t i=0;i<grid_.size();++i) grid_[i] = scalef*log(grid_[i]); + for(index_t i=0; i<grid_.size(); ++i) grid_[i] = scalef*log(grid_[i]); } } -void Grid::setMinToZero(){ +void Grid::setMinToZero() { double min=grid_[0]; - for(index_t i=1;i<grid_.size();++i) if(grid_[i]<min) min=grid_[i]; - for(index_t i=0;i<grid_.size();++i) grid_[i] -= min; + for(index_t i=1; i<grid_.size(); ++i) if(grid_[i]<min) min=grid_[i]; + for(index_t i=0; i<grid_.size(); ++i) grid_[i] -= min; } -void Grid::applyFunctionAllValuesAndDerivatives( double (*func)(double val), double (*funcder)(double valder) ){ - if(usederiv_){ - for(index_t i=0;i<grid_.size();++i){ - grid_[i]=func(grid_[i]); - for(unsigned j=0;j<dimension_;++j) der_[i][j]=funcder(der_[i][j]); - } +void Grid::applyFunctionAllValuesAndDerivatives( double (*func)(double val), double (*funcder)(double valder) ) { + if(usederiv_) { + for(index_t i=0; i<grid_.size(); ++i) { + grid_[i]=func(grid_[i]); + for(unsigned j=0; j<dimension_; ++j) der_[i][j]=funcder(der_[i][j]); + } } else { - for(index_t i=0;i<grid_.size();++i) grid_[i]=func(grid_[i]); - } -} - -void Grid::writeHeader(OFile& ofile){ - for(unsigned i=0;i<dimension_;++i){ - ofile.addConstantField("min_" + argnames[i]); - ofile.addConstantField("max_" + argnames[i]); - ofile.addConstantField("nbins_" + argnames[i]); - ofile.addConstantField("periodic_" + argnames[i]); - } -} - -void Grid::writeToFile(OFile& ofile){ - vector<double> xx(dimension_); - vector<double> der(dimension_); - double f; - writeHeader(ofile); - for(index_t i=0;i<getSize();++i){ - xx=getPoint(i); - if(usederiv_){f=getValueAndDerivatives(i,der);} - else{f=getValue(i);} - if(i>0 && dimension_>1 && getIndices(i)[dimension_-2]==0) ofile.printf("\n"); - for(unsigned j=0;j<dimension_;++j){ - ofile.printField("min_" + argnames[j], str_min_[j] ); - ofile.printField("max_" + argnames[j], str_max_[j] ); - ofile.printField("nbins_" + argnames[j], static_cast<int>(nbin_[j]) ); - if( pbc_[j] ) ofile.printField("periodic_" + argnames[j], "true" ); - else ofile.printField("periodic_" + argnames[j], "false" ); - } - for(unsigned j=0;j<dimension_;++j){ ofile.fmtField(" "+fmt_); ofile.printField(argnames[j],xx[j]); } - ofile.fmtField(" "+fmt_); ofile.printField(funcname,f); - if(usederiv_) for(unsigned j=0;j<dimension_;++j){ ofile.fmtField(" "+fmt_); ofile.printField("der_" + argnames[j] ,der[j]); } - ofile.printField(); - } -} - -void Grid::writeCubeFile(OFile& ofile, const double& lunit){ + for(index_t i=0; i<grid_.size(); ++i) grid_[i]=func(grid_[i]); + } +} + +void Grid::writeHeader(OFile& ofile) { + for(unsigned i=0; i<dimension_; ++i) { + ofile.addConstantField("min_" + argnames[i]); + ofile.addConstantField("max_" + argnames[i]); + ofile.addConstantField("nbins_" + argnames[i]); + ofile.addConstantField("periodic_" + argnames[i]); + } +} + +void Grid::writeToFile(OFile& ofile) { + vector<double> xx(dimension_); + vector<double> der(dimension_); + double f; + writeHeader(ofile); + for(index_t i=0; i<getSize(); ++i) { + xx=getPoint(i); + if(usederiv_) {f=getValueAndDerivatives(i,der);} + else {f=getValue(i);} + if(i>0 && dimension_>1 && getIndices(i)[dimension_-2]==0) ofile.printf("\n"); + for(unsigned j=0; j<dimension_; ++j) { + ofile.printField("min_" + argnames[j], str_min_[j] ); + ofile.printField("max_" + argnames[j], str_max_[j] ); + ofile.printField("nbins_" + argnames[j], static_cast<int>(nbin_[j]) ); + if( pbc_[j] ) ofile.printField("periodic_" + argnames[j], "true" ); + else ofile.printField("periodic_" + argnames[j], "false" ); + } + for(unsigned j=0; j<dimension_; ++j) { ofile.fmtField(" "+fmt_); ofile.printField(argnames[j],xx[j]); } + ofile.fmtField(" "+fmt_); ofile.printField(funcname,f); + if(usederiv_) for(unsigned j=0; j<dimension_; ++j) { ofile.fmtField(" "+fmt_); ofile.printField("der_" + argnames[j],der[j]); } + ofile.printField(); + } +} + +void Grid::writeCubeFile(OFile& ofile, const double& lunit) { plumed_assert( dimension_==3 ); ofile.printf("PLUMED CUBE FILE\n"); ofile.printf("OUTER LOOP: X, MIDDLE LOOP: Y, INNER LOOP: Z\n"); // Number of atoms followed by position of origin (origin set so that center of grid is in center of cell) - ofile.printf("%d %f %f %f\n",1,-0.5*lunit*(max_[0]-min_[0]),-0.5*lunit*(max_[1]-min_[1]),-0.5*lunit*(max_[2]-min_[2])); - ofile.printf("%u %f %f %f\n",nbin_[0],lunit*dx_[0],0.0,0.0); // Number of bins in each direction followed by + ofile.printf("%d %f %f %f\n",1,-0.5*lunit*(max_[0]-min_[0]),-0.5*lunit*(max_[1]-min_[1]),-0.5*lunit*(max_[2]-min_[2])); + ofile.printf("%u %f %f %f\n",nbin_[0],lunit*dx_[0],0.0,0.0); // Number of bins in each direction followed by ofile.printf("%u %f %f %f\n",nbin_[1],0.0,lunit*dx_[1],0.0); // shape of voxel ofile.printf("%u %f %f %f\n",nbin_[2],0.0,0.0,lunit*dx_[2]); ofile.printf("%d %f %f %f\n",1,0.0,0.0,0.0); // Fake atom otherwise VMD doesn't work std::vector<unsigned> pp(3); - for(pp[0]=0;pp[0]<nbin_[0];++pp[0]){ - for(pp[1]=0;pp[1]<nbin_[1];++pp[1]){ - for(pp[2]=0;pp[2]<nbin_[2];++pp[2]){ - ofile.printf("%f ",getValue(pp) ); - if(pp[2]%6==5) ofile.printf("\n"); - } - ofile.printf("\n"); - } + for(pp[0]=0; pp[0]<nbin_[0]; ++pp[0]) { + for(pp[1]=0; pp[1]<nbin_[1]; ++pp[1]) { + for(pp[2]=0; pp[2]<nbin_[2]; ++pp[2]) { + ofile.printf("%f ",getValue(pp) ); + if(pp[2]%6==5) ofile.printf("\n"); + } + ofile.printf("\n"); + } } } -Grid* Grid::create(const std::string& funcl, const std::vector<Value*> & args, IFile& ifile, - const vector<std::string> & gmin,const vector<std::string> & gmax, - const vector<unsigned> & nbin,bool dosparse, bool dospline, bool doder){ +Grid* Grid::create(const std::string& funcl, const std::vector<Value*> & args, IFile& ifile, + const vector<std::string> & gmin,const vector<std::string> & gmax, + const vector<unsigned> & nbin,bool dosparse, bool dospline, bool doder) { Grid* grid=Grid::create(funcl,args,ifile,dosparse,dospline,doder); std::vector<unsigned> cbin( grid->getNbin() ); std::vector<std::string> cmin( grid->getMin() ), cmax( grid->getMax() ); - for(unsigned i=0;i<args.size();++i){ - plumed_massert( cmin[i]==gmin[i], "mismatched grid min" ); - plumed_massert( cmax[i]==gmax[i], "mismatched grid max" ); - if( args[i]->isPeriodic() ){ - plumed_massert( cbin[i]==nbin[i], "mismatched grid nbins" ); - } else { - plumed_massert( (cbin[i]-1)==nbin[i], "mismatched grid nbins"); - } + for(unsigned i=0; i<args.size(); ++i) { + plumed_massert( cmin[i]==gmin[i], "mismatched grid min" ); + plumed_massert( cmax[i]==gmax[i], "mismatched grid max" ); + if( args[i]->isPeriodic() ) { + plumed_massert( cbin[i]==nbin[i], "mismatched grid nbins" ); + } else { + plumed_massert( (cbin[i]-1)==nbin[i], "mismatched grid nbins"); + } } return grid; } Grid* Grid::create(const std::string& funcl, const std::vector<Value*> & args, IFile& ifile, bool dosparse, bool dospline, bool doder) { - Grid* grid=NULL; - unsigned nvar=args.size(); bool hasder=false; std::string pstring; - std::vector<int> gbin1(nvar); std::vector<unsigned> gbin(nvar); - std::vector<std::string> labels(nvar),gmin(nvar),gmax(nvar); - std::vector<std::string> fieldnames; ifile.scanFieldList( fieldnames ); - // Retrieve names for fields - for(unsigned i=0;i<args.size();++i) labels[i]=args[i]->getName(); - // And read the stuff from the header - plumed_massert( ifile.FieldExist( funcl ) , "no column labelled " + funcl + " in in grid input"); - for(unsigned i=0;i<args.size();++i){ - ifile.scanField( "min_" + labels[i], gmin[i]); - ifile.scanField( "max_" + labels[i], gmax[i]); - ifile.scanField( "periodic_" + labels[i], pstring ); - ifile.scanField( "nbins_" + labels[i], gbin1[i]); - plumed_assert( gbin1[i]>0 ); - if( args[i]->isPeriodic() ){ - plumed_massert( pstring=="true", "input value is periodic but grid is not"); - std::string pmin, pmax; - args[i]->getDomain( pmin, pmax ); gbin[i]=gbin1[i]; - if( pmin!=gmin[i] || pmax!=gmax[i] ) plumed_merror("mismatch between grid boundaries and periods of values"); - } else { - gbin[i]=gbin1[i]-1; // Note header in grid file indicates one more bin that there should be when data is not periodic - plumed_massert( pstring=="false", "input value is not periodic but grid is"); - } - hasder=ifile.FieldExist( "der_" + args[i]->getName() ); - if( doder && !hasder ) plumed_merror("missing derivatives from grid file"); - for(unsigned j=0;j<fieldnames.size();++j){ - for(unsigned k=i+1;k<args.size();++k){ - if( fieldnames[j]==labels[k] ) plumed_merror("arguments in input are not in same order as in grid file"); - } - if( fieldnames[j]==labels[i] ) break; - } - } - - if(!dosparse){grid=new Grid(funcl,args,gmin,gmax,gbin,dospline,doder);} - else{grid=new SparseGrid(funcl,args,gmin,gmax,gbin,dospline,doder);} - - vector<double> xx(nvar),dder(nvar); - vector<double> dx=grid->getDx(); - double f,x; - while( ifile.scanField(funcl,f) ){ - for(unsigned i=0;i<nvar;++i){ - ifile.scanField(labels[i],x); xx[i]=x+dx[i]/2.0; - ifile.scanField( "min_" + labels[i], gmin[i]); - ifile.scanField( "max_" + labels[i], gmax[i]); - ifile.scanField( "nbins_" + labels[i], gbin1[i]); - ifile.scanField( "periodic_" + labels[i], pstring ); - } - if(hasder){ for(unsigned i=0;i<nvar;++i){ ifile.scanField( "der_" + args[i]->getName(), dder[i] ); } } - index_t index=grid->getIndex(xx); - if(doder){grid->setValueAndDerivatives(index,f,dder);} - else{grid->setValue(index,f);} - ifile.scanField(); - } - return grid; + Grid* grid=NULL; + unsigned nvar=args.size(); bool hasder=false; std::string pstring; + std::vector<int> gbin1(nvar); std::vector<unsigned> gbin(nvar); + std::vector<std::string> labels(nvar),gmin(nvar),gmax(nvar); + std::vector<std::string> fieldnames; ifile.scanFieldList( fieldnames ); +// Retrieve names for fields + for(unsigned i=0; i<args.size(); ++i) labels[i]=args[i]->getName(); +// And read the stuff from the header + plumed_massert( ifile.FieldExist( funcl ), "no column labelled " + funcl + " in in grid input"); + for(unsigned i=0; i<args.size(); ++i) { + ifile.scanField( "min_" + labels[i], gmin[i]); + ifile.scanField( "max_" + labels[i], gmax[i]); + ifile.scanField( "periodic_" + labels[i], pstring ); + ifile.scanField( "nbins_" + labels[i], gbin1[i]); + plumed_assert( gbin1[i]>0 ); + if( args[i]->isPeriodic() ) { + plumed_massert( pstring=="true", "input value is periodic but grid is not"); + std::string pmin, pmax; + args[i]->getDomain( pmin, pmax ); gbin[i]=gbin1[i]; + if( pmin!=gmin[i] || pmax!=gmax[i] ) plumed_merror("mismatch between grid boundaries and periods of values"); + } else { + gbin[i]=gbin1[i]-1; // Note header in grid file indicates one more bin that there should be when data is not periodic + plumed_massert( pstring=="false", "input value is not periodic but grid is"); + } + hasder=ifile.FieldExist( "der_" + args[i]->getName() ); + if( doder && !hasder ) plumed_merror("missing derivatives from grid file"); + for(unsigned j=0; j<fieldnames.size(); ++j) { + for(unsigned k=i+1; k<args.size(); ++k) { + if( fieldnames[j]==labels[k] ) plumed_merror("arguments in input are not in same order as in grid file"); + } + if( fieldnames[j]==labels[i] ) break; + } + } + + if(!dosparse) {grid=new Grid(funcl,args,gmin,gmax,gbin,dospline,doder);} + else {grid=new SparseGrid(funcl,args,gmin,gmax,gbin,dospline,doder);} + + vector<double> xx(nvar),dder(nvar); + vector<double> dx=grid->getDx(); + double f,x; + while( ifile.scanField(funcl,f) ) { + for(unsigned i=0; i<nvar; ++i) { + ifile.scanField(labels[i],x); xx[i]=x+dx[i]/2.0; + ifile.scanField( "min_" + labels[i], gmin[i]); + ifile.scanField( "max_" + labels[i], gmax[i]); + ifile.scanField( "nbins_" + labels[i], gbin1[i]); + ifile.scanField( "periodic_" + labels[i], pstring ); + } + if(hasder) { for(unsigned i=0; i<nvar; ++i) { ifile.scanField( "der_" + args[i]->getName(), dder[i] ); } } + index_t index=grid->getIndex(xx); + if(doder) {grid->setValueAndDerivatives(index,f,dder);} + else {grid->setValue(index,f);} + ifile.scanField(); + } + return grid; } // Sparse version of grid with map -void SparseGrid::clear(){ - map_.clear(); +void SparseGrid::clear() { + map_.clear(); } -Grid::index_t SparseGrid::getSize() const{ - return map_.size(); +Grid::index_t SparseGrid::getSize() const { + return map_.size(); } Grid::index_t SparseGrid::getMaxSize() const { - return maxsize_; + return maxsize_; } double Grid::getDifferenceFromContour( const std::vector<double>& x, std::vector<double>& der ) const { - return getValueAndDerivatives( x, der ) - contour_location; + return getValueAndDerivatives( x, der ) - contour_location; } void Grid::findSetOfPointsOnContour(const double& target, const std::vector<bool>& nosearch, - unsigned& npoints, std::vector<std::vector<double> >& points ){ - // Set contour location for function - contour_location=target; - // Resize points to maximum possible value - points.resize( dimension_*maxsize_ ); - - // Two points for search - std::vector<unsigned> ind(dimension_); - std::vector<double> direction( dimension_, 0 ); - - // Run over whole grid - npoints=0; RootFindingBase<Grid> mymin( this ); - for(unsigned i=0;i<maxsize_;++i){ - for(unsigned j=0;j<dimension_;++j) ind[j]=getIndices(i)[j]; - - // Get the value of a point on the grid - double val1=getValue(i) - target; - - // Now search for contour in each direction - bool edge=false; - for(unsigned j=0;j<dimension_;++j){ - if( nosearch[j] ) continue ; - // Make sure we don't search at the edge of the grid - if( !pbc_[j] && (ind[j]+1)==nbin_[j] ) continue; - else if( (ind[j]+1)==nbin_[j] ){ edge=true; ind[j]=0; } - else ind[j]+=1; - double val2=getValue(ind) - target; - if( val1*val2<0 ){ - // Use initial point location as first guess for search - points[npoints].resize(dimension_); for(unsigned k=0;k<dimension_;++k) points[npoints][k]=getPoint(i)[k]; - // Setup direction vector - direction[j]=0.999999999*dx_[j]; - // And do proper search for contour point - mymin.linesearch( direction, points[npoints], &Grid::getDifferenceFromContour ); - direction[j]=0.0; npoints++; - } - if( pbc_[j] && edge ){ edge=false; ind[j]=nbin_[j]-1; } - else ind[j]-=1; - } - } -} - -double SparseGrid::getValue(index_t index)const{ - plumed_assert(index<maxsize_); - double value=0.0; - const auto it=map_.find(index); - if(it!=map_.end()) value=it->second; - return value; + unsigned& npoints, std::vector<std::vector<double> >& points ) { +// Set contour location for function + contour_location=target; +// Resize points to maximum possible value + points.resize( dimension_*maxsize_ ); + +// Two points for search + std::vector<unsigned> ind(dimension_); + std::vector<double> direction( dimension_, 0 ); + +// Run over whole grid + npoints=0; RootFindingBase<Grid> mymin( this ); + for(unsigned i=0; i<maxsize_; ++i) { + for(unsigned j=0; j<dimension_; ++j) ind[j]=getIndices(i)[j]; + + // Get the value of a point on the grid + double val1=getValue(i) - target; + + // Now search for contour in each direction + bool edge=false; + for(unsigned j=0; j<dimension_; ++j) { + if( nosearch[j] ) continue ; + // Make sure we don't search at the edge of the grid + if( !pbc_[j] && (ind[j]+1)==nbin_[j] ) continue; + else if( (ind[j]+1)==nbin_[j] ) { edge=true; ind[j]=0; } + else ind[j]+=1; + double val2=getValue(ind) - target; + if( val1*val2<0 ) { + // Use initial point location as first guess for search + points[npoints].resize(dimension_); for(unsigned k=0; k<dimension_; ++k) points[npoints][k]=getPoint(i)[k]; + // Setup direction vector + direction[j]=0.999999999*dx_[j]; + // And do proper search for contour point + mymin.linesearch( direction, points[npoints], &Grid::getDifferenceFromContour ); + direction[j]=0.0; npoints++; + } + if( pbc_[j] && edge ) { edge=false; ind[j]=nbin_[j]-1; } + else ind[j]-=1; + } + } +} + +double SparseGrid::getValue(index_t index)const { + plumed_assert(index<maxsize_); + double value=0.0; + const auto it=map_.find(index); + if(it!=map_.end()) value=it->second; + return value; } double SparseGrid::getValueAndDerivatives - (index_t index, vector<double>& der)const{ - plumed_assert(index<maxsize_ && usederiv_ && der.size()==dimension_); - double value=0.0; - for(unsigned int i=0;i<dimension_;++i) der[i]=0.0; - const auto it=map_.find(index); - if(it!=map_.end()) value=it->second; - const auto itder=der_.find(index); - if(itder!=der_.end()) der=itder->second; - return value; +(index_t index, vector<double>& der)const { + plumed_assert(index<maxsize_ && usederiv_ && der.size()==dimension_); + double value=0.0; + for(unsigned int i=0; i<dimension_; ++i) der[i]=0.0; + const auto it=map_.find(index); + if(it!=map_.end()) value=it->second; + const auto itder=der_.find(index); + if(itder!=der_.end()) der=itder->second; + return value; } -void SparseGrid::setValue(index_t index, double value){ - plumed_assert(index<maxsize_ && !usederiv_); - map_[index]=value; +void SparseGrid::setValue(index_t index, double value) { + plumed_assert(index<maxsize_ && !usederiv_); + map_[index]=value; } void SparseGrid::setValueAndDerivatives - (index_t index, double value, vector<double>& der){ - plumed_assert(index<maxsize_ && usederiv_ && der.size()==dimension_); - map_[index]=value; - der_[index]=der; +(index_t index, double value, vector<double>& der) { + plumed_assert(index<maxsize_ && usederiv_ && der.size()==dimension_); + map_[index]=value; + der_[index]=der; } -void SparseGrid::addValue(index_t index, double value){ - plumed_assert(index<maxsize_ && !usederiv_); - map_[index]+=value; +void SparseGrid::addValue(index_t index, double value) { + plumed_assert(index<maxsize_ && !usederiv_); + map_[index]+=value; } void SparseGrid::addValueAndDerivatives - (index_t index, double value, vector<double>& der){ - plumed_assert(index<maxsize_ && usederiv_ && der.size()==dimension_); - map_[index]+=value; - der_[index].resize(dimension_); - for(unsigned int i=0;i<dimension_;++i) der_[index][i]+=der[i]; -} - -void SparseGrid::writeToFile(OFile& ofile){ - vector<double> xx(dimension_); - vector<double> der(dimension_); - double f; - writeHeader(ofile); - ofile.fmtField(" "+fmt_); - for(const auto & it : map_){ - index_t i=it.first; - xx=getPoint(i); - if(usederiv_){f=getValueAndDerivatives(i,der);} - else{f=getValue(i);} - if(i>0 && dimension_>1 && getIndices(i)[dimension_-2]==0) ofile.printf("\n"); - for(unsigned j=0;j<dimension_;++j){ - ofile.printField("min_" + argnames[j], str_min_[j] ); - ofile.printField("max_" + argnames[j], str_max_[j] ); - ofile.printField("nbins_" + argnames[j], static_cast<int>(nbin_[j]) ); - if( pbc_[j] ) ofile.printField("periodic_" + argnames[j], "true" ); - else ofile.printField("periodic_" + argnames[j], "false" ); - } - for(unsigned j=0;j<dimension_;++j) ofile.printField(argnames[j],xx[j]); - ofile.printField(funcname, f); - if(usederiv_){ for(unsigned j=0;j<dimension_;++j) ofile.printField("der_" + argnames[j],der[j]); } - ofile.printField(); - } -} - - -void Grid::projectOnLowDimension(double &val, std::vector<int> &vHigh, WeightBase * ptr2obj ){ - unsigned i=0; - for(i=0;i<vHigh.size();i++){ - if(vHigh[i]<0){// this bin needs to be integrated out - // parallelize here??? - for(unsigned j=0;j<(getNbin())[i];j++){ - vHigh[i]=int(j); - projectOnLowDimension(val,vHigh,ptr2obj); // recursive function: this is the core of the mechanism - vHigh[i]=-1; - } - return; // - } +(index_t index, double value, vector<double>& der) { + plumed_assert(index<maxsize_ && usederiv_ && der.size()==dimension_); + map_[index]+=value; + der_[index].resize(dimension_); + for(unsigned int i=0; i<dimension_; ++i) der_[index][i]+=der[i]; +} + +void SparseGrid::writeToFile(OFile& ofile) { + vector<double> xx(dimension_); + vector<double> der(dimension_); + double f; + writeHeader(ofile); + ofile.fmtField(" "+fmt_); + for(const auto & it : map_) { + index_t i=it.first; + xx=getPoint(i); + if(usederiv_) {f=getValueAndDerivatives(i,der);} + else {f=getValue(i);} + if(i>0 && dimension_>1 && getIndices(i)[dimension_-2]==0) ofile.printf("\n"); + for(unsigned j=0; j<dimension_; ++j) { + ofile.printField("min_" + argnames[j], str_min_[j] ); + ofile.printField("max_" + argnames[j], str_max_[j] ); + ofile.printField("nbins_" + argnames[j], static_cast<int>(nbin_[j]) ); + if( pbc_[j] ) ofile.printField("periodic_" + argnames[j], "true" ); + else ofile.printField("periodic_" + argnames[j], "false" ); + } + for(unsigned j=0; j<dimension_; ++j) ofile.printField(argnames[j],xx[j]); + ofile.printField(funcname, f); + if(usederiv_) { for(unsigned j=0; j<dimension_; ++j) ofile.printField("der_" + argnames[j],der[j]); } + ofile.printField(); + } +} + + +void Grid::projectOnLowDimension(double &val, std::vector<int> &vHigh, WeightBase * ptr2obj ) { + unsigned i=0; + for(i=0; i<vHigh.size(); i++) { + if(vHigh[i]<0) { // this bin needs to be integrated out + // parallelize here??? + for(unsigned j=0; j<(getNbin())[i]; j++) { + vHigh[i]=int(j); + projectOnLowDimension(val,vHigh,ptr2obj); // recursive function: this is the core of the mechanism + vHigh[i]=-1; + } + return; // + } + } + // when there are no more bin to dig in then retrieve the value + if(i==vHigh.size()) { + //std::cerr<<"POINT: "; + //for(unsigned j=0;j<vHigh.size();j++){ + // std::cerr<<vHigh[j]<<" "; + //} + std::vector<unsigned> vv(vHigh.size()); + for(unsigned j=0; j<vHigh.size(); j++)vv[j]=unsigned(vHigh[j]); + // + // this is the real assignment !!!!! (hack this to have bias or other stuff) + // + + // this case: produce fes + //val+=exp(beta*getValue(vv)) ; + double myv=getValue(vv); + val=ptr2obj->projectInnerLoop(val,myv) ; + // to be added: bias (same as before without negative sign) + //std::cerr<<" VAL: "<<val <<endl; + } +} + +Grid Grid::project(const std::vector<std::string> & proj, WeightBase *ptr2obj ) { + // find extrema only for the projection + vector<string> smallMin,smallMax; + vector<unsigned> smallBin; + vector<unsigned> dimMapping; + vector<bool> smallIsPeriodic; + vector<string> smallName; + + // check if the two key methods are there + WeightBase* pp = dynamic_cast<WeightBase*>(ptr2obj); + if (!pp)plumed_merror("This WeightBase is not complete: you need a projectInnerLoop and projectOuterLoop "); + + for(unsigned j=0; j<proj.size(); j++) { + for(unsigned i=0; i<getArgNames().size(); i++) { + if(proj[j]==getArgNames()[i]) { + unsigned offset; + // note that at sizetime the non periodic dimension get a bin more + if(getIsPeriodic()[i]) {offset=0;} else {offset=1;} + smallMax.push_back(getMax()[i]); + smallMin.push_back(getMin()[i]); + smallBin.push_back(getNbin()[i]-offset); + smallIsPeriodic.push_back(getIsPeriodic()[i]); + dimMapping.push_back(i); + smallName.push_back(getArgNames()[i]); + break; + } } - // when there are no more bin to dig in then retrieve the value - if(i==vHigh.size()){ - //std::cerr<<"POINT: "; - //for(unsigned j=0;j<vHigh.size();j++){ - // std::cerr<<vHigh[j]<<" "; - //} - std::vector<unsigned> vv(vHigh.size()); - for(unsigned j=0;j<vHigh.size();j++)vv[j]=unsigned(vHigh[j]); - // - // this is the real assignment !!!!! (hack this to have bias or other stuff) - // - - // this case: produce fes - //val+=exp(beta*getValue(vv)) ; - double myv=getValue(vv); - val=ptr2obj->projectInnerLoop(val,myv) ; - // to be added: bias (same as before without negative sign) - //std::cerr<<" VAL: "<<val <<endl; + } + Grid smallgrid("projection",smallName,smallMin,smallMax,smallBin,false,false,true,smallIsPeriodic,smallMin,smallMax); + // check that the two grids are commensurate + for(unsigned i=0; i<dimMapping.size(); i++) { + plumed_massert( (smallgrid.getMax())[i] == (getMax())[dimMapping[i]], "the two input grids are not compatible in max" ); + plumed_massert( (smallgrid.getMin())[i] == (getMin())[dimMapping[i]], "the two input grids are not compatible in min" ); + plumed_massert( (smallgrid.getNbin())[i]== (getNbin())[dimMapping[i]], "the two input grids are not compatible in bin" ); + } + vector<unsigned> toBeIntegrated; + for(unsigned i=0; i<getArgNames().size(); i++) { + bool doappend=true; + for(unsigned j=0; j<dimMapping.size(); j++) { + if(dimMapping[j]==i) {doappend=false; break;} } + if(doappend)toBeIntegrated.push_back(i); + } + //for(unsigned i=0;i<dimMapping.size();i++ ){ + // cerr<<"Dimension to preserve "<<dimMapping[i]<<endl; + //} + //for(unsigned i=0;i<toBeIntegrated.size();i++ ){ + // cerr<<"Dimension to integrate "<<toBeIntegrated[i]<<endl; + //} + + // loop over all the points in the Grid, find the corresponding fixed index, rotate over all the other ones + for(unsigned i=0; i<smallgrid.getSize(); i++) { + std::vector<unsigned> v; + v=smallgrid.getIndices(i); + std::vector<int> vHigh((getArgNames()).size(),-1); + for(unsigned j=0; j<dimMapping.size(); j++)vHigh[dimMapping[j]]=int(v[j]); + // the vector vhigh now contains at the beginning the index of the low dimension and -1 for the values that need to be integrated + double initval=0.; + projectOnLowDimension(initval,vHigh, ptr2obj); + smallgrid.setValue(i,initval); + } + // reset to zero just for biasing (this option can be evtl enabled in a future...) + //double vmin;vmin=-smallgrid.getMinValue()+1; + for(unsigned i=0; i<smallgrid.getSize(); i++) { + // //if(dynamic_cast<BiasWeight*>(ptr2obj)){ + // // smallgrid.addValue(i,vmin);// go to 1 + // //} + double vv=smallgrid.getValue(i); + smallgrid.setValue(i,ptr2obj->projectOuterLoop(vv)); + // //if(dynamic_cast<BiasWeight*>(ptr2obj)){ + // // smallgrid.addValue(i,-vmin);// bring back to the value + // //} + } + + return smallgrid; } -Grid Grid::project(const std::vector<std::string> & proj , WeightBase *ptr2obj ){ - // find extrema only for the projection - vector<string> smallMin,smallMax; - vector<unsigned> smallBin; - vector<unsigned> dimMapping; - vector<bool> smallIsPeriodic; - vector<string> smallName; - - // check if the two key methods are there - WeightBase* pp = dynamic_cast<WeightBase*>(ptr2obj); - if (!pp)plumed_merror("This WeightBase is not complete: you need a projectInnerLoop and projectOuterLoop "); - - for(unsigned j=0;j<proj.size();j++){ - for(unsigned i=0;i<getArgNames().size();i++){ - if(proj[j]==getArgNames()[i]){ - unsigned offset; - // note that at sizetime the non periodic dimension get a bin more - if(getIsPeriodic()[i]){offset=0;}else{offset=1;} - smallMax.push_back(getMax()[i]); - smallMin.push_back(getMin()[i]); - smallBin.push_back(getNbin()[i]-offset); - smallIsPeriodic.push_back(getIsPeriodic()[i]); - dimMapping.push_back(i); - smallName.push_back(getArgNames()[i]); - break; - } - } - } - Grid smallgrid("projection",smallName,smallMin,smallMax,smallBin,false,false,true,smallIsPeriodic,smallMin,smallMax); - // check that the two grids are commensurate - for(unsigned i=0;i<dimMapping.size();i++){ - plumed_massert( (smallgrid.getMax())[i] == (getMax())[dimMapping[i]], "the two input grids are not compatible in max" ); - plumed_massert( (smallgrid.getMin())[i] == (getMin())[dimMapping[i]], "the two input grids are not compatible in min" ); - plumed_massert( (smallgrid.getNbin())[i]== (getNbin())[dimMapping[i]], "the two input grids are not compatible in bin" ); - } - vector<unsigned> toBeIntegrated; - for(unsigned i=0;i<getArgNames().size();i++){ - bool doappend=true; - for(unsigned j=0;j<dimMapping.size();j++){ - if(dimMapping[j]==i){doappend=false; break;} - } - if(doappend)toBeIntegrated.push_back(i); - } - //for(unsigned i=0;i<dimMapping.size();i++ ){ - // cerr<<"Dimension to preserve "<<dimMapping[i]<<endl; - //} - //for(unsigned i=0;i<toBeIntegrated.size();i++ ){ - // cerr<<"Dimension to integrate "<<toBeIntegrated[i]<<endl; - //} - - // loop over all the points in the Grid, find the corresponding fixed index, rotate over all the other ones - for(unsigned i=0;i<smallgrid.getSize();i++){ - std::vector<unsigned> v; - v=smallgrid.getIndices(i); - std::vector<int> vHigh((getArgNames()).size(),-1); - for(unsigned j=0;j<dimMapping.size();j++)vHigh[dimMapping[j]]=int(v[j]); - // the vector vhigh now contains at the beginning the index of the low dimension and -1 for the values that need to be integrated - double initval=0.; - projectOnLowDimension(initval,vHigh, ptr2obj); - smallgrid.setValue(i,initval); - } - // reset to zero just for biasing (this option can be evtl enabled in a future...) - //double vmin;vmin=-smallgrid.getMinValue()+1; - for(unsigned i=0;i<smallgrid.getSize();i++){ - // //if(dynamic_cast<BiasWeight*>(ptr2obj)){ - // // smallgrid.addValue(i,vmin);// go to 1 - // //} - double vv=smallgrid.getValue(i); - smallgrid.setValue(i,ptr2obj->projectOuterLoop(vv)); - // //if(dynamic_cast<BiasWeight*>(ptr2obj)){ - // // smallgrid.addValue(i,-vmin);// bring back to the value - // //} - } - - return smallgrid; -} - -double Grid::integrate( std::vector<unsigned>& npoints ){ +double Grid::integrate( std::vector<unsigned>& npoints ) { plumed_dbg_assert( npoints.size()==dimension_ ); plumed_assert( dospline_ ); unsigned ntotgrid=1; double box_vol=1.0; std::vector<double> ispacing( npoints.size() ); - for(unsigned j=0;j<dimension_;++j){ - if( !pbc_[j] ){ - ispacing[j] = ( max_[j] - dx_[j] - min_[j] ) / static_cast<double>( npoints[j] ); - npoints[j]+=1; - } else { - ispacing[j] = ( max_[j] - min_[j] ) / static_cast<double>( npoints[j] ); - } - ntotgrid*=npoints[j]; box_vol*=ispacing[j]; + for(unsigned j=0; j<dimension_; ++j) { + if( !pbc_[j] ) { + ispacing[j] = ( max_[j] - dx_[j] - min_[j] ) / static_cast<double>( npoints[j] ); + npoints[j]+=1; + } else { + ispacing[j] = ( max_[j] - min_[j] ) / static_cast<double>( npoints[j] ); + } + ntotgrid*=npoints[j]; box_vol*=ispacing[j]; } std::vector<double> vals( dimension_ ); std::vector<unsigned> t_index( dimension_ ); double integral=0.0; - for(unsigned i=0;i<ntotgrid;++i){ - t_index[0]=(i%npoints[0]); - unsigned kk=i; - for(unsigned j=1;j<dimension_-1;++j){ kk=(kk-t_index[j-1])/npoints[i-1]; t_index[j]=(kk%npoints[i]); } - if( dimension_>=2 ) t_index[dimension_-1]=((kk-t_index[dimension_-1])/npoints[dimension_-2]); + for(unsigned i=0; i<ntotgrid; ++i) { + t_index[0]=(i%npoints[0]); + unsigned kk=i; + for(unsigned j=1; j<dimension_-1; ++j) { kk=(kk-t_index[j-1])/npoints[i-1]; t_index[j]=(kk%npoints[i]); } + if( dimension_>=2 ) t_index[dimension_-1]=((kk-t_index[dimension_-1])/npoints[dimension_-2]); - for(unsigned j=0;j<dimension_;++j) vals[j]=min_[j] + t_index[j]*ispacing[j]; + for(unsigned j=0; j<dimension_; ++j) vals[j]=min_[j] + t_index[j]*ispacing[j]; - integral += getValue( vals ); + integral += getValue( vals ); } return box_vol*integral; } -void Grid::mpiSumValuesAndDerivatives( Communicator& comm ){ - comm.Sum( grid_ ); for(unsigned i=0;i<der_.size();++i) comm.Sum( der_[i] ); +void Grid::mpiSumValuesAndDerivatives( Communicator& comm ) { + comm.Sum( grid_ ); for(unsigned i=0; i<der_.size(); ++i) comm.Sum( der_[i] ); } } diff --git a/src/tools/Grid.h b/src/tools/Grid.h index 7641a2971..2e6c13415 100644 --- a/src/tools/Grid.h +++ b/src/tools/Grid.h @@ -27,32 +27,32 @@ #include <map> #include <cmath> -namespace PLMD{ +namespace PLMD { // simple function to enable various weighting -class WeightBase{ - public: - virtual double projectInnerLoop(double &input, double &v)=0; - virtual double projectOuterLoop(double &v)=0; - virtual ~WeightBase(){} +class WeightBase { +public: + virtual double projectInnerLoop(double &input, double &v)=0; + virtual double projectOuterLoop(double &v)=0; + virtual ~WeightBase() {} }; -class BiasWeight:public WeightBase{ - public: - double beta,invbeta; - explicit BiasWeight(double v){beta=v;invbeta=1./beta;} - double projectInnerLoop(double &input, double &v){return input+exp(beta*v);} - double projectOuterLoop(double &v){return -invbeta*std::log(v);} +class BiasWeight:public WeightBase { +public: + double beta,invbeta; + explicit BiasWeight(double v) {beta=v; invbeta=1./beta;} + double projectInnerLoop(double &input, double &v) {return input+exp(beta*v);} + double projectOuterLoop(double &v) {return -invbeta*std::log(v);} }; -class ProbWeight:public WeightBase{ - public: - double beta,invbeta; - explicit ProbWeight(double v){beta=v;invbeta=1./beta;} - double projectInnerLoop(double &input, double &v){return input+v;} - double projectOuterLoop(double &v){return -invbeta*std::log(v);} +class ProbWeight:public WeightBase { +public: + double beta,invbeta; + explicit ProbWeight(double v) {beta=v; invbeta=1./beta;} + double projectInnerLoop(double &input, double &v) {return input+v;} + double projectOuterLoop(double &v) {return -invbeta*std::log(v);} }; @@ -67,200 +67,200 @@ class KernelFunctions; class Communicator; /// \ingroup TOOLBOX -class Grid +class Grid { public: // we use a size_t here // should be 8 bytes on all 64-bit machines // and more portable than "unsigned long long" - typedef size_t index_t; + typedef size_t index_t; // to restore old implementation (unsigned) use the following instead: // typedef unsigned index_t; private: - double contour_location; - std::vector<double> grid_; - std::vector< std::vector<double> > der_; + double contour_location; + std::vector<double> grid_; + std::vector< std::vector<double> > der_; protected: - std::string funcname; - std::vector<std::string> argnames; - std::vector<std::string> str_min_, str_max_; - std::vector<double> min_,max_,dx_; - std::vector<unsigned> nbin_; - std::vector<bool> pbc_; - index_t maxsize_; - unsigned dimension_; - bool dospline_, usederiv_; - std::string fmt_; // format for output - /// get "neighbors" for spline - std::vector<index_t> getSplineNeighbors(const std::vector<unsigned> & indices)const; + std::string funcname; + std::vector<std::string> argnames; + std::vector<std::string> str_min_, str_max_; + std::vector<double> min_,max_,dx_; + std::vector<unsigned> nbin_; + std::vector<bool> pbc_; + index_t maxsize_; + unsigned dimension_; + bool dospline_, usederiv_; + std::string fmt_; // format for output +/// get "neighbors" for spline + std::vector<index_t> getSplineNeighbors(const std::vector<unsigned> & indices)const; public: - /// clear grid - virtual void clear(); - /// this constructor here is Value-aware - Grid(const std::string& funcl, const std::vector<Value*> & args, const std::vector<std::string> & gmin, - const std::vector<std::string> & gmax, const std::vector<unsigned> & nbin, bool dospline, - bool usederiv, bool doclear=true); - /// this constructor here is not Value-aware - Grid(const std::string& funcl, const std::vector<std::string> &names, const std::vector<std::string> & gmin, - const std::vector<std::string> & gmax, const std::vector<unsigned> & nbin, bool dospline, - bool usederiv, bool doclear, const std::vector<bool> &isperiodic, const std::vector<std::string> &pmin, - const std::vector<std::string> &pmax ); - /// this is the real initializator - void Init(const std::string & funcl, const std::vector<std::string> &names, const std::vector<std::string> & gmin, - const std::vector<std::string> & gmax, const std::vector<unsigned> & nbin, bool dospline, bool usederiv, - bool doclear, const std::vector<bool> &isperiodic, const std::vector<std::string> &pmin, const std::vector<std::string> &pmax); +/// clear grid + virtual void clear(); +/// this constructor here is Value-aware + Grid(const std::string& funcl, const std::vector<Value*> & args, const std::vector<std::string> & gmin, + const std::vector<std::string> & gmax, const std::vector<unsigned> & nbin, bool dospline, + bool usederiv, bool doclear=true); +/// this constructor here is not Value-aware + Grid(const std::string& funcl, const std::vector<std::string> &names, const std::vector<std::string> & gmin, + const std::vector<std::string> & gmax, const std::vector<unsigned> & nbin, bool dospline, + bool usederiv, bool doclear, const std::vector<bool> &isperiodic, const std::vector<std::string> &pmin, + const std::vector<std::string> &pmax ); +/// this is the real initializator + void Init(const std::string & funcl, const std::vector<std::string> &names, const std::vector<std::string> & gmin, + const std::vector<std::string> & gmax, const std::vector<unsigned> & nbin, bool dospline, bool usederiv, + bool doclear, const std::vector<bool> &isperiodic, const std::vector<std::string> &pmin, const std::vector<std::string> &pmax); /// get lower boundary - std::vector<std::string> getMin() const; + std::vector<std::string> getMin() const; /// get upper boundary - std::vector<std::string> getMax() const; + std::vector<std::string> getMax() const; /// get bin size - std::vector<double> getDx() const; + std::vector<double> getDx() const; /// get bin volume - double getBinVolume() const; + double getBinVolume() const; /// get number of bins - std::vector<unsigned> getNbin() const; + std::vector<unsigned> getNbin() const; /// get if periodic - std::vector<bool> getIsPeriodic() const; + std::vector<bool> getIsPeriodic() const; /// get grid dimension - unsigned getDimension() const; -/// get argument names of this grid - std::vector<std::string> getArgNames() const; - -/// methods to handle grid indices - std::vector<unsigned> getIndices(index_t index) const; - std::vector<unsigned> getIndices(const std::vector<double> & x) const; - index_t getIndex(const std::vector<unsigned> & indices) const; - index_t getIndex(const std::vector<double> & x) const; - std::vector<double> getPoint(index_t index) const; - std::vector<double> getPoint(const std::vector<unsigned> & indices) const; - std::vector<double> getPoint(const std::vector<double> & x) const; + unsigned getDimension() const; +/// get argument names of this grid + std::vector<std::string> getArgNames() const; + +/// methods to handle grid indices + std::vector<unsigned> getIndices(index_t index) const; + std::vector<unsigned> getIndices(const std::vector<double> & x) const; + index_t getIndex(const std::vector<unsigned> & indices) const; + index_t getIndex(const std::vector<double> & x) const; + std::vector<double> getPoint(index_t index) const; + std::vector<double> getPoint(const std::vector<unsigned> & indices) const; + std::vector<double> getPoint(const std::vector<double> & x) const; /// faster versions relying on preallocated vectors - void getPoint(index_t index,std::vector<double> & point) const; - void getPoint(const std::vector<unsigned> & indices,std::vector<double> & point) const; - void getPoint(const std::vector<double> & x,std::vector<double> & point) const; + void getPoint(index_t index,std::vector<double> & point) const; + void getPoint(const std::vector<unsigned> & indices,std::vector<double> & point) const; + void getPoint(const std::vector<double> & x,std::vector<double> & point) const; /// get neighbors - std::vector<index_t> getNeighbors(index_t index,const std::vector<unsigned> & neigh) const; - std::vector<index_t> getNeighbors(const std::vector<unsigned> & indices,const std::vector<unsigned> & neigh) const; - std::vector<index_t> getNeighbors(const std::vector<double> & x,const std::vector<unsigned> & neigh) const; + std::vector<index_t> getNeighbors(index_t index,const std::vector<unsigned> & neigh) const; + std::vector<index_t> getNeighbors(const std::vector<unsigned> & indices,const std::vector<unsigned> & neigh) const; + std::vector<index_t> getNeighbors(const std::vector<double> & x,const std::vector<unsigned> & neigh) const; /// write header for grid file - void writeHeader(OFile& file); + void writeHeader(OFile& file); /// read grid from file - static Grid* create(const std::string&,const std::vector<Value*>&,IFile&,bool,bool,bool); + static Grid* create(const std::string&,const std::vector<Value*>&,IFile&,bool,bool,bool); /// read grid from file and check boundaries are what is expected from input - static Grid* create(const std::string&,const std::vector<Value*>&, IFile&, - const std::vector<std::string>&,const std::vector<std::string>&, - const std::vector<unsigned>&,bool,bool,bool); + static Grid* create(const std::string&,const std::vector<Value*>&, IFile&, + const std::vector<std::string>&,const std::vector<std::string>&, + const std::vector<unsigned>&,bool,bool,bool); /// get grid size - virtual index_t getSize() const; + virtual index_t getSize() const; /// get grid value - virtual double getValue(index_t index) const; - virtual double getValue(const std::vector<unsigned> & indices) const; - virtual double getValue(const std::vector<double> & x) const; + virtual double getValue(index_t index) const; + virtual double getValue(const std::vector<unsigned> & indices) const; + virtual double getValue(const std::vector<double> & x) const; /// get minimum value virtual double getMinValue() const; /// get maximum value virtual double getMaxValue() const; /// get grid value and derivatives - virtual double getValueAndDerivatives(index_t index, std::vector<double>& der) const ; - virtual double getValueAndDerivatives(const std::vector<unsigned> & indices, std::vector<double>& der) const; - virtual double getValueAndDerivatives(const std::vector<double> & x, std::vector<double>& der) const; + virtual double getValueAndDerivatives(index_t index, std::vector<double>& der) const ; + virtual double getValueAndDerivatives(const std::vector<unsigned> & indices, std::vector<double>& der) const; + virtual double getValueAndDerivatives(const std::vector<double> & x, std::vector<double>& der) const; /// Get the difference from the contour - double getDifferenceFromContour(const std::vector<double> & x, std::vector<double>& der) const ; + double getDifferenceFromContour(const std::vector<double> & x, std::vector<double>& der) const ; /// Find a set of points on a contour in the function - void findSetOfPointsOnContour(const double& target, const std::vector<bool>& nosearch, unsigned& npoints, std::vector<std::vector<double> >& points ); + void findSetOfPointsOnContour(const double& target, const std::vector<bool>& nosearch, unsigned& npoints, std::vector<std::vector<double> >& points ); -/// set grid value - virtual void setValue(index_t index, double value); - virtual void setValue(const std::vector<unsigned> & indices, double value); +/// set grid value + virtual void setValue(index_t index, double value); + virtual void setValue(const std::vector<unsigned> & indices, double value); /// set grid value and derivatives - virtual void setValueAndDerivatives(index_t index, double value, std::vector<double>& der); - virtual void setValueAndDerivatives(const std::vector<unsigned> & indices, double value, std::vector<double>& der); + virtual void setValueAndDerivatives(index_t index, double value, std::vector<double>& der); + virtual void setValueAndDerivatives(const std::vector<unsigned> & indices, double value, std::vector<double>& der); /// add to grid value - virtual void addValue(index_t index, double value); - virtual void addValue(const std::vector<unsigned> & indices, double value); + virtual void addValue(index_t index, double value); + virtual void addValue(const std::vector<unsigned> & indices, double value); /// add to grid value and derivatives - virtual void addValueAndDerivatives(index_t index, double value, std::vector<double>& der); - virtual void addValueAndDerivatives(const std::vector<unsigned> & indices, double value, std::vector<double>& der); + virtual void addValueAndDerivatives(index_t index, double value, std::vector<double>& der); + virtual void addValueAndDerivatives(const std::vector<unsigned> & indices, double value, std::vector<double>& der); /// Scale all grid values and derivatives by a constant factor - virtual void scaleAllValuesAndDerivatives( const double& scalef ); -/// Takes the scalef times the logarithm of all grid values and derivatives - virtual void logAllValuesAndDerivatives( const double& scalef ); + virtual void scaleAllValuesAndDerivatives( const double& scalef ); +/// Takes the scalef times the logarithm of all grid values and derivatives + virtual void logAllValuesAndDerivatives( const double& scalef ); /// Set the minimum value of the grid to zero and translates accordingly - virtual void setMinToZero(); -/// apply function: takes pointer to function that accepts a double and apply - virtual void applyFunctionAllValuesAndDerivatives( double (*func)(double val), double (*funcder)(double valder) ); + virtual void setMinToZero(); +/// apply function: takes pointer to function that accepts a double and apply + virtual void applyFunctionAllValuesAndDerivatives( double (*func)(double val), double (*funcder)(double valder) ); /// add a kernel function to the grid - void addKernel( const KernelFunctions& kernel ); + void addKernel( const KernelFunctions& kernel ); /// dump grid on file - virtual void writeToFile(OFile&); + virtual void writeToFile(OFile&); /// dump grid to gaussian cube file - void writeCubeFile(OFile&, const double& lunit); + void writeCubeFile(OFile&, const double& lunit); - virtual ~Grid(){} + virtual ~Grid() {} -/// project a high dimensional grid onto a low dimensional one: this should be changed at some time +/// project a high dimensional grid onto a low dimensional one: this should be changed at some time /// to enable many types of weighting - Grid project( const std::vector<std::string> & proj , WeightBase *ptr2obj ); - void projectOnLowDimension(double &val , std::vector<int> &varHigh, WeightBase* ptr2obj ); + Grid project( const std::vector<std::string> & proj, WeightBase *ptr2obj ); + void projectOnLowDimension(double &val, std::vector<int> &varHigh, WeightBase* ptr2obj ); /// set output format - void setOutputFmt(const std::string & ss){fmt_=ss;} + void setOutputFmt(const std::string & ss) {fmt_=ss;} /// Integrate the function calculated on the grid - double integrate( std::vector<unsigned>& npoints ); + double integrate( std::vector<unsigned>& npoints ); /// - void mpiSumValuesAndDerivatives( Communicator& comm ); + void mpiSumValuesAndDerivatives( Communicator& comm ); }; - + class SparseGrid : public Grid { - std::map<index_t,double> map_; - std::map< index_t,std::vector<double> > der_; - - protected: - void clear(); - - public: - SparseGrid(const std::string& funcl, const std::vector<Value*> & args, const std::vector<std::string> & gmin, - const std::vector<std::string> & gmax, - const std::vector<unsigned> & nbin, bool dospline, bool usederiv): - Grid(funcl,args,gmin,gmax,nbin,dospline,usederiv,false){} - - index_t getSize() const; - index_t getMaxSize() const; + std::map<index_t,double> map_; + std::map< index_t,std::vector<double> > der_; + +protected: + void clear(); + +public: + SparseGrid(const std::string& funcl, const std::vector<Value*> & args, const std::vector<std::string> & gmin, + const std::vector<std::string> & gmax, + const std::vector<unsigned> & nbin, bool dospline, bool usederiv): + Grid(funcl,args,gmin,gmax,nbin,dospline,usederiv,false) {} + + index_t getSize() const; + index_t getMaxSize() const; /// this is to access to Grid:: version of these methods (allowing overloading of virtual methods) - using Grid::getValue; - using Grid::getValueAndDerivatives; - using Grid::setValue; - using Grid::setValueAndDerivatives; - using Grid::addValue; - using Grid::addValueAndDerivatives; - - /// get grid value - double getValue(index_t index) const; + using Grid::getValue; + using Grid::getValueAndDerivatives; + using Grid::setValue; + using Grid::setValueAndDerivatives; + using Grid::addValue; + using Grid::addValueAndDerivatives; + +/// get grid value + double getValue(index_t index) const; /// get grid value and derivatives - double getValueAndDerivatives(index_t index, std::vector<double>& der) const; + double getValueAndDerivatives(index_t index, std::vector<double>& der) const; -/// set grid value - void setValue(index_t index, double value); +/// set grid value + void setValue(index_t index, double value); /// set grid value and derivatives - void setValueAndDerivatives(index_t index, double value, std::vector<double>& der); + void setValueAndDerivatives(index_t index, double value, std::vector<double>& der); /// add to grid value - void addValue(index_t index, double value); + void addValue(index_t index, double value); /// add to grid value and derivatives - void addValueAndDerivatives(index_t index, double value, std::vector<double>& der); + void addValueAndDerivatives(index_t index, double value, std::vector<double>& der); /// dump grid on file - void writeToFile(OFile&); + void writeToFile(OFile&); - virtual ~SparseGrid(){} + virtual ~SparseGrid() {} }; } diff --git a/src/tools/HistogramBead.cpp b/src/tools/HistogramBead.cpp index c3bd83199..bdef4556f 100644 --- a/src/tools/HistogramBead.cpp +++ b/src/tools/HistogramBead.cpp @@ -25,9 +25,9 @@ #include "Tools.h" #include "Keywords.h" -namespace PLMD{ +namespace PLMD { -//+PLUMEDOC INTERNAL histogrambead +//+PLUMEDOC INTERNAL histogrambead /* A function that can be used to calculate whether quantities are between fixed upper and lower bounds. @@ -36,32 +36,32 @@ for that variable using a process called kernel density estimation: \f[ P(s) = \sum_i K\left( \frac{s - s_i}{w} \right) -\f] +\f] In this equation \f$K\f$ is a symmetric funciton that must integrate to one that is often -called a kernel function and \f$w\f$ is a smearing parameter. From a pdf calculated using +called a kernel function and \f$w\f$ is a smearing parameter. From a pdf calculated using kernel density estimation we can calculate the number/fraction of values between an upper and lower bound using: \f[ w(s) = \int_a^b \sum_i K\left( \frac{s - s_i}{w} \right) -\f] +\f] -All the input to calculate a quantity like \f$w(s)\f$ is generally provided through a single +All the input to calculate a quantity like \f$w(s)\f$ is generally provided through a single keyword that will have the following form: KEYWORD={TYPE UPPER=\f$a\f$ LOWER=\f$b\f$ SMEAR=\f$\frac{w}{b-a}\f$} This will calculate the number of values between \f$a\f$ and \f$b\f$. To calculate -the fraction of values you add the word NORM to the input specification. If the +the fraction of values you add the word NORM to the input specification. If the function keyword SMEAR is not present \f$w\f$ is set equal to \f$0.5(b-a)\f$. Finally, type should specify one of the kernel types that is present in plumed. These are listed in the table below: <table align=center frame=void width=95%% cellpadding=5%%> -<tr> -<td> TYPE </td> <td> FUNCTION </td> -</tr> <tr> +<tr> +<td> TYPE </td> <td> FUNCTION </td> +</tr> <tr> <td> GAUSSIAN </td> <td> \f$\frac{1}{\sqrt{2\pi}w} \exp\left( -\frac{(s-s_i)^2}{2w^2} \right)\f$ </td> </tr> <tr> <td> TRIANGULAR </td> <td> \f$ \frac{1}{2w} \left( 1. - \left| \frac{s-s_i}{w} \right| \right) \quad \frac{s-s_i}{w}<1 \f$ </td> @@ -74,34 +74,34 @@ is to say the number of values between \f$a\f$ and \f$b\f$, the number of values something like KEYWORD={TYPE UPPER=\f$a\f$ LOWER=\f$b\f$ NBINS=\f$n\f$ SMEAR=\f$\frac{w}{n(b-a)}\f$} - -This specification would calculate the following vector of quantities: + +This specification would calculate the following vector of quantities: \f[ -w_j(s) = \int_{a + \frac{j-1}{n}(b-a)}^{a + \frac{j}{n}(b-a)} \sum_i K\left( \frac{s - s_i}{w} \right) +w_j(s) = \int_{a + \frac{j-1}{n}(b-a)}^{a + \frac{j}{n}(b-a)} \sum_i K\left( \frac{s - s_i}{w} \right) \f] */ //+ENDPLUMEDOC -void HistogramBead::registerKeywords( Keywords& keys ){ +void HistogramBead::registerKeywords( Keywords& keys ) { keys.add("compulsory","LOWER","the lower boundary for this particular bin"); keys.add("compulsory","UPPER","the upper boundary for this particular bin"); keys.add("compulsory","SMEAR","0.5","the ammount to smear the Gaussian for each value in the distribution"); } HistogramBead::HistogramBead(): -init(false), -lowb(0.0), -highb(0.0), -width(0.0), -cutoff(std::numeric_limits<double>::max()), -type(gaussian), -periodicity(unset), -min(0.0), -max(0.0), -max_minus_min(0.0), -inv_max_minus_min(0.0) + init(false), + lowb(0.0), + highb(0.0), + width(0.0), + cutoff(std::numeric_limits<double>::max()), + type(gaussian), + periodicity(unset), + min(0.0), + max(0.0), + max_minus_min(0.0), + inv_max_minus_min(0.0) { } @@ -111,7 +111,7 @@ std::string HistogramBead::description() const { return ostr.str(); } -void HistogramBead::generateBins( const std::string& params, std::vector<std::string>& bins ){ +void HistogramBead::generateBins( const std::string& params, std::vector<std::string>& bins ) { std::vector<std::string> data=Tools::getWords(params); plumed_massert(data.size()>=1,"There is no input for this keyword"); @@ -124,78 +124,78 @@ void HistogramBead::generateBins( const std::string& params, std::vector<std::st plumed_massert(found_r,"Lower bound for histogram not specified"); found_r=Tools::parse(data,"UPPER",range[1]); plumed_massert(found_r,"Upper bound for histogram not specified"); - plumed_massert(range[0]<range[1],"Range specification is dubious"); + plumed_massert(range[0]<range[1],"Range specification is dubious"); bool found_b=Tools::parse(data,"SMEAR",smear); - if(!found_b){ Tools::convert(0.5,smear); } + if(!found_b) { Tools::convert(0.5,smear); } std::string lb,ub; double delr = ( range[1]-range[0] ) / static_cast<double>( nbins ); - for(unsigned i=0;i<nbins;++i){ - Tools::convert( range[0]+i*delr, lb ); - Tools::convert( range[0]+(i+1)*delr, ub ); - bins.push_back( name + " " + "LOWER=" + lb + " " + "UPPER=" + ub + " " + "SMEAR=" + smear ); + for(unsigned i=0; i<nbins; ++i) { + Tools::convert( range[0]+i*delr, lb ); + Tools::convert( range[0]+(i+1)*delr, ub ); + bins.push_back( name + " " + "LOWER=" + lb + " " + "UPPER=" + ub + " " + "SMEAR=" + smear ); } plumed_assert(bins.size()==nbins); } -void HistogramBead::set( const std::string& params, std::string& errormsg ){ +void HistogramBead::set( const std::string& params, std::string& errormsg ) { std::vector<std::string> data=Tools::getWords(params); if(data.size()<1) errormsg="No input has been specified"; std::string name=data[0]; const double DP2CUTOFF=6.25; - if(name=="GAUSSIAN"){ type=gaussian; cutoff=sqrt(2.0*DP2CUTOFF); } - else if(name=="TRIANGULAR"){ type=triangular; cutoff=1.; } - else plumed_merror("cannot understand kernel type " + name ); + if(name=="GAUSSIAN") { type=gaussian; cutoff=sqrt(2.0*DP2CUTOFF); } + else if(name=="TRIANGULAR") { type=triangular; cutoff=1.; } + else plumed_merror("cannot understand kernel type " + name ); double smear; bool found_r=Tools::parse(data,"LOWER",lowb); if( !found_r ) errormsg="Lower bound has not been specified use LOWER"; found_r=Tools::parse(data,"UPPER",highb); - if( !found_r ) errormsg="Upper bound has not been specified use UPPER"; - if( lowb>=highb ) errormsg="Lower bound is higher than upper bound"; - + if( !found_r ) errormsg="Upper bound has not been specified use UPPER"; + if( lowb>=highb ) errormsg="Lower bound is higher than upper bound"; + smear=0.5; Tools::parse(data,"SMEAR",smear); width=smear*(highb-lowb); init=true; } -void HistogramBead::set( double l, double h, double w){ - init=true; lowb=l; highb=h; width=w; +void HistogramBead::set( double l, double h, double w) { + init=true; lowb=l; highb=h; width=w; const double DP2CUTOFF=6.25; if( type==gaussian ) cutoff=sqrt(2.0*DP2CUTOFF); else if( type==triangular ) cutoff=1.; else plumed_error(); -} +} -void HistogramBead::setKernelType( const std::string& ktype ){ +void HistogramBead::setKernelType( const std::string& ktype ) { if(ktype=="gaussian") type=gaussian; else if(ktype=="triangular") type=triangular; - else plumed_merror("cannot understand kernel type " + ktype ); -} + else plumed_merror("cannot understand kernel type " + ktype ); +} double HistogramBead::calculate( double x, double& df ) const { - plumed_dbg_assert(init && periodicity!=unset ); + plumed_dbg_assert(init && periodicity!=unset ); double lowB, upperB, f; - if( type==gaussian ){ - lowB = difference( x, lowb ) / ( sqrt(2.0) * width ); - upperB = difference( x, highb ) / ( sqrt(2.0) * width ); - df = ( exp( -lowB*lowB ) - exp( -upperB*upperB ) ) / ( sqrt(2*pi)*width ); - f = 0.5*( erf( upperB ) - erf( lowB ) ); - } else if( type==triangular ){ - lowB = ( difference( x, lowb ) / width ); - upperB = ( difference( x, highb ) / width ); - df=0; - if( fabs(lowB)<1. ) df = (1 - fabs(lowB)) / width; - if( fabs(upperB)<1. ) df -= (1 - fabs(upperB)) / width; - if (upperB<=-1. || lowB >=1.){ - f=0.; - } else { - double ia, ib; - if( lowB>-1.0 ){ ia=lowB; }else{ ia=-1.0; } - if( upperB<1.0 ){ ib=upperB; } else{ ib=1.0; } - f = (ib*(2.-fabs(ib))-ia*(2.-fabs(ia)))*0.5; - } + if( type==gaussian ) { + lowB = difference( x, lowb ) / ( sqrt(2.0) * width ); + upperB = difference( x, highb ) / ( sqrt(2.0) * width ); + df = ( exp( -lowB*lowB ) - exp( -upperB*upperB ) ) / ( sqrt(2*pi)*width ); + f = 0.5*( erf( upperB ) - erf( lowB ) ); + } else if( type==triangular ) { + lowB = ( difference( x, lowb ) / width ); + upperB = ( difference( x, highb ) / width ); + df=0; + if( fabs(lowB)<1. ) df = (1 - fabs(lowB)) / width; + if( fabs(upperB)<1. ) df -= (1 - fabs(upperB)) / width; + if (upperB<=-1. || lowB >=1.) { + f=0.; + } else { + double ia, ib; + if( lowB>-1.0 ) { ia=lowB; } else { ia=-1.0; } + if( upperB<1.0 ) { ib=upperB; } else { ib=1.0; } + f = (ib*(2.-fabs(ib))-ia*(2.-fabs(ia)))*0.5; + } } else { - plumed_merror("function type does not exist"); - } + plumed_merror("function type does not exist"); + } return f; } @@ -204,59 +204,59 @@ double HistogramBead::calculateWithCutoff( double x, double& df ) const { double lowB, upperB, f; lowB = difference( x, lowb ) / width ; upperB = difference( x, highb ) / width; - if( upperB<=-cutoff || lowB>=cutoff ){ df=0; return 0; } - - if( type==gaussian ){ - lowB /= sqrt(2.0); upperB /= sqrt(2.0); - df = ( exp( -lowB*lowB ) - exp( -upperB*upperB ) ) / ( sqrt(2*pi)*width ); - f = 0.5*( erf( upperB ) - erf( lowB ) ); - } else if( type==triangular ){ - df=0; - if( fabs(lowB)<1. ) df = (1 - fabs(lowB)) / width; - if( fabs(upperB)<1. ) df -= (1 - fabs(upperB)) / width; - if (upperB<=-1. || lowB >=1.){ - f=0.; - } else { - double ia, ib; - if( lowB>-1.0 ){ ia=lowB; }else{ ia=-1.0; } - if( upperB<1.0 ){ ib=upperB; } else{ ib=1.0; } - f = (ib*(2.-fabs(ib))-ia*(2.-fabs(ia)))*0.5; - } + if( upperB<=-cutoff || lowB>=cutoff ) { df=0; return 0; } + + if( type==gaussian ) { + lowB /= sqrt(2.0); upperB /= sqrt(2.0); + df = ( exp( -lowB*lowB ) - exp( -upperB*upperB ) ) / ( sqrt(2*pi)*width ); + f = 0.5*( erf( upperB ) - erf( lowB ) ); + } else if( type==triangular ) { + df=0; + if( fabs(lowB)<1. ) df = (1 - fabs(lowB)) / width; + if( fabs(upperB)<1. ) df -= (1 - fabs(upperB)) / width; + if (upperB<=-1. || lowB >=1.) { + f=0.; + } else { + double ia, ib; + if( lowB>-1.0 ) { ia=lowB; } else { ia=-1.0; } + if( upperB<1.0 ) { ib=upperB; } else { ib=1.0; } + f = (ib*(2.-fabs(ib))-ia*(2.-fabs(ia)))*0.5; + } } else { - plumed_merror("function type does not exist"); + plumed_merror("function type does not exist"); } return f; } double HistogramBead::lboundDerivative( const double& x ) const { double lowB; - if( type==gaussian ){ - lowB = difference( x, lowb ) / ( sqrt(2.0) * width ); - return exp( -lowB*lowB ) / ( sqrt(2*pi)*width ); - } else if ( type==triangular ){ - plumed_error(); + if( type==gaussian ) { + lowB = difference( x, lowb ) / ( sqrt(2.0) * width ); + return exp( -lowB*lowB ) / ( sqrt(2*pi)*width ); + } else if ( type==triangular ) { + plumed_error(); // lowB = fabs( difference( x, lowb ) / width ); // if( lowB<1 ) return ( 1 - (lowB) ) / 2*width; // else return 0; } else { - plumed_merror("function type does not exist"); + plumed_merror("function type does not exist"); } return 0; } -double HistogramBead::uboundDerivative( const double& x ) const { +double HistogramBead::uboundDerivative( const double& x ) const { plumed_dbg_assert(init && periodicity!=unset ); double upperB; - if( type==gaussian ){ - upperB = difference( x, highb ) / ( sqrt(2.0) * width ); - return exp( -upperB*upperB ) / ( sqrt(2*pi)*width ); - } else if ( type==triangular ){ - plumed_error(); + if( type==gaussian ) { + upperB = difference( x, highb ) / ( sqrt(2.0) * width ); + return exp( -upperB*upperB ) / ( sqrt(2*pi)*width ); + } else if ( type==triangular ) { + plumed_error(); // upperB = fabs( difference( x, highb ) / width ); -// if( upperB<1 ) return ( 1 - (upperB) ) / 2*width; +// if( upperB<1 ) return ( 1 - (upperB) ) / 2*width; // else return 0; } else { - plumed_merror("function type does not exist"); + plumed_merror("function type does not exist"); } return 0; } diff --git a/src/tools/HistogramBead.h b/src/tools/HistogramBead.h index 44fe12054..aae33470c 100644 --- a/src/tools/HistogramBead.h +++ b/src/tools/HistogramBead.h @@ -34,39 +34,39 @@ class Log; /** \ingroup TOOLBOX -A class for calculating whether or not values are within a given range using : \f$ \sum_i \int_a^b G( s_i, \sigma*(b-a) ) \f$ -*/ - -class HistogramBead{ -private: - bool init; - double lowb; - double highb; - double width; - double cutoff; - enum {gaussian,triangular} type; - enum {unset,periodic,notperiodic} periodicity; - double min, max, max_minus_min, inv_max_minus_min; - double difference( const double& d1, const double& d2 ) const ; +A class for calculating whether or not values are within a given range using : \f$ \sum_i \int_a^b G( s_i, \sigma*(b-a) ) \f$ +*/ + +class HistogramBead { +private: + bool init; + double lowb; + double highb; + double width; + double cutoff; + enum {gaussian,triangular} type; + enum {unset,periodic,notperiodic} periodicity; + double min, max, max_minus_min, inv_max_minus_min; + double difference( const double& d1, const double& d2 ) const ; public: - static void registerKeywords( Keywords& keys ); - static void generateBins( const std::string& params, std::vector<std::string>& bins ); - HistogramBead(); - std::string description() const ; - bool hasBeenSet() const; - void isNotPeriodic(); - void isPeriodic( const double& mlow, const double& mhigh ); - void setKernelType( const std::string& ktype ); - void set(const std::string& params, std::string& errormsg); - void set(double l, double h, double w); - double calculate(double x, double&df) const; - double calculateWithCutoff( double x, double& df ) const; - double lboundDerivative( const double& x ) const; - double uboundDerivative( const double& x ) const; - double getlowb() const ; - double getbigb() const ; - double getCutoff() const ; -}; + static void registerKeywords( Keywords& keys ); + static void generateBins( const std::string& params, std::vector<std::string>& bins ); + HistogramBead(); + std::string description() const ; + bool hasBeenSet() const; + void isNotPeriodic(); + void isPeriodic( const double& mlow, const double& mhigh ); + void setKernelType( const std::string& ktype ); + void set(const std::string& params, std::string& errormsg); + void set(double l, double h, double w); + double calculate(double x, double&df) const; + double calculateWithCutoff( double x, double& df ) const; + double lboundDerivative( const double& x ) const; + double uboundDerivative( const double& x ) const; + double getlowb() const ; + double getbigb() const ; + double getCutoff() const ; +}; inline bool HistogramBead::hasBeenSet() const { @@ -74,12 +74,12 @@ bool HistogramBead::hasBeenSet() const { } inline -void HistogramBead::isNotPeriodic(){ +void HistogramBead::isNotPeriodic() { periodicity=notperiodic; } inline -void HistogramBead::isPeriodic( const double& mlow, const double& mhigh ){ +void HistogramBead::isPeriodic( const double& mlow, const double& mhigh ) { periodicity=periodic; min=mlow; max=mhigh; max_minus_min=max-min; plumed_massert(max_minus_min>0, "your function has a very strange domain?"); @@ -88,7 +88,7 @@ void HistogramBead::isPeriodic( const double& mlow, const double& mhigh ){ inline double HistogramBead::getlowb() const { return lowb; } - + inline double HistogramBead::getbigb() const { return highb; } @@ -97,9 +97,9 @@ double HistogramBead::getCutoff() const { return cutoff*width; } inline double HistogramBead::difference( const double& d1, const double& d2 ) const { - if(periodicity==notperiodic){ + if(periodicity==notperiodic) { return d2-d1; - } else if(periodicity==periodic){ + } else if(periodicity==periodic) { // Make sure the point is in the target range double newx=d1*inv_max_minus_min; newx=Tools::pbc(newx); diff --git a/src/tools/IFile.cpp b/src/tools/IFile.cpp index c1334fb5c..5cd326135 100644 --- a/src/tools/IFile.cpp +++ b/src/tools/IFile.cpp @@ -36,12 +36,12 @@ #include <zlib.h> #endif -namespace PLMD{ +namespace PLMD { -size_t IFile::llread(char*ptr,size_t s){ +size_t IFile::llread(char*ptr,size_t s) { plumed_assert(fp); size_t r; - if(gzfp){ + if(gzfp) { #ifdef __PLUMED_HAS_ZLIB int rr=gzread(gzFile(gzfp),ptr,s); if(rr==0) eof=true; @@ -58,22 +58,22 @@ size_t IFile::llread(char*ptr,size_t s){ return r; } -IFile& IFile::advanceField(){ +IFile& IFile::advanceField() { plumed_assert(!inMiddleOfField); std::string line; bool done=false; - while(!done){ + while(!done) { getline(line); - if(!*this){return *this;} + if(!*this) {return *this;} std::vector<std::string> words=Tools::getWords(line); - if(words.size()>=2 && words[0]=="#!" && words[1]=="FIELDS"){ + if(words.size()>=2 && words[0]=="#!" && words[1]=="FIELDS") { fields.clear(); - for(unsigned i=2;i<words.size();i++){ + for(unsigned i=2; i<words.size(); i++) { Field field; field.name=words[i]; fields.push_back(field); } - } else if(words.size()==4 && words[0]=="#!" && words[1]=="SET"){ + } else if(words.size()==4 && words[0]=="#!" && words[1]=="SET") { Field field; field.name=words[2]; field.value=words[3]; @@ -81,20 +81,20 @@ IFile& IFile::advanceField(){ fields.push_back(field); } else { unsigned nf=0; - for(unsigned i=0;i<fields.size();i++) if(!fields[i].constant) nf++; + for(unsigned i=0; i<fields.size(); i++) if(!fields[i].constant) nf++; Tools::trimComments(line); words=Tools::getWords(line); - if( words.size()==nf ){ - unsigned j=0; - for(unsigned i=0;i<fields.size();i++){ - if(fields[i].constant) continue; - fields[i].value=words[j]; - fields[i].read=false; - j++; - } - done=true; + if( words.size()==nf ) { + unsigned j=0; + for(unsigned i=0; i<fields.size(); i++) { + if(fields[i].constant) continue; + fields[i].value=words[j]; + fields[i].read=false; + j++; + } + done=true; } else if( !words.empty() ) { - plumed_merror(getPath() + " mismatch between number of fields in file and expected number"); + plumed_merror(getPath() + " mismatch between number of fields in file and expected number"); } } } @@ -102,7 +102,7 @@ IFile& IFile::advanceField(){ return *this; } -IFile& IFile::open(const std::string&path){ +IFile& IFile::open(const std::string&path) { plumed_massert(!cloned,"file "+path+" appears to be cloned"); eof=false; err=false; @@ -111,7 +111,7 @@ IFile& IFile::open(const std::string&path){ bool do_exist=FileExist(path); plumed_massert(do_exist,"file " + path + " cannot be found"); fp=std::fopen(const_cast<char*>(this->path.c_str()),"r"); - if(Tools::extension(this->path)=="gz"){ + if(Tools::extension(this->path)=="gz") { #ifdef __PLUMED_HAS_ZLIB gzfp=(void*)gzopen(const_cast<char*>(this->path.c_str()),"r"); #else @@ -122,24 +122,24 @@ IFile& IFile::open(const std::string&path){ return *this; } -IFile& IFile::scanFieldList(std::vector<std::string>&s){ +IFile& IFile::scanFieldList(std::vector<std::string>&s) { if(!inMiddleOfField) advanceField(); if(!*this) return *this; s.clear(); - for(unsigned i=0;i<fields.size();i++) + for(unsigned i=0; i<fields.size(); i++) s.push_back(fields[i].name); return *this; } -bool IFile::FieldExist(const std::string& s){ - std::vector<std::string> slist; - scanFieldList(slist); - int mycount = (int) std::count(slist.begin(), slist.end(), s); - if(mycount>0) return true; - else return false; +bool IFile::FieldExist(const std::string& s) { + std::vector<std::string> slist; + scanFieldList(slist); + int mycount = (int) std::count(slist.begin(), slist.end(), s); + if(mycount>0) return true; + else return false; } -IFile& IFile::scanField(const std::string&name,std::string&str){ +IFile& IFile::scanField(const std::string&name,std::string&str) { if(!inMiddleOfField) advanceField(); if(!*this) return *this; unsigned i=findField(name); @@ -148,40 +148,40 @@ IFile& IFile::scanField(const std::string&name,std::string&str){ return *this; } -IFile& IFile::scanField(const std::string&name,double &x){ +IFile& IFile::scanField(const std::string&name,double &x) { std::string str; scanField(name,str); if(*this) Tools::convert(str,x); return *this; } -IFile& IFile::scanField(const std::string&name,int &x){ +IFile& IFile::scanField(const std::string&name,int &x) { std::string str; scanField(name,str); if(*this) Tools::convert(str,x); return *this; } -IFile& IFile::scanField(Value* val){ +IFile& IFile::scanField(Value* val) { double ff=NAN; // this is to be sure a NAN value is replaced upon failure scanField( val->getName(), ff ); val->set( ff ); - if( FieldExist("min_" + val->getName() ) ){ - std::string min, max; - scanField("min_" + val->getName(), min ); - scanField("max_" + val->getName(), max ); - val->setDomain( min, max ); + if( FieldExist("min_" + val->getName() ) ) { + std::string min, max; + scanField("min_" + val->getName(), min ); + scanField("max_" + val->getName(), max ); + val->setDomain( min, max ); } else { - val->setNotPeriodic(); + val->setNotPeriodic(); } return *this; } -IFile& IFile::scanField(){ - if(!ignoreFields){ - for(unsigned i=0;i<fields.size();i++){ - plumed_massert(fields[i].read,"field "+fields[i].name+" was not read: all the fields need to be read otherwise you could miss important infos" ); - } +IFile& IFile::scanField() { + if(!ignoreFields) { + for(unsigned i=0; i<fields.size(); i++) { + plumed_massert(fields[i].read,"field "+fields[i].name+" was not read: all the fields need to be read otherwise you could miss important infos" ); + } } inMiddleOfField=false; return *this; @@ -194,25 +194,25 @@ IFile::IFile(): { } -IFile::~IFile(){ +IFile::~IFile() { if(inMiddleOfField) std::cerr<<"WARNING: IFile closed in the middle of reading. seems strange!\n"; } -IFile& IFile::getline(std::string &str){ +IFile& IFile::getline(std::string &str) { char tmp=0; str=""; fpos_t pos; fgetpos(fp,&pos); - while(llread(&tmp,1)==1 && tmp && tmp!='\n' && tmp!='\r' && !eof && !err){ + while(llread(&tmp,1)==1 && tmp && tmp!='\n' && tmp!='\r' && !eof && !err) { str+=tmp; } - if(tmp=='\r'){ + if(tmp=='\r') { llread(&tmp,1); plumed_massert(tmp=='\n',"plumed only accepts \\n (unix) or \\r\\n (dos) new lines"); } - if(eof && noEOL){ - if(str.length()>0) eof=false; - } else if(eof || err || tmp!='\n'){ + if(eof && noEOL) { + if(str.length()>0) eof=false; + } else if(eof || err || tmp!='\n') { eof = true; str=""; if(!err) fsetpos(fp,&pos); @@ -227,28 +227,28 @@ IFile& IFile::getline(std::string &str){ return *this; } -unsigned IFile::findField(const std::string&name)const{ +unsigned IFile::findField(const std::string&name)const { unsigned i; - for(i=0;i<fields.size();i++) if(fields[i].name==name) break; + for(i=0; i<fields.size(); i++) if(fields[i].name==name) break; if(i>=fields.size()) plumed_merror(name); return i; } -void IFile::reset(bool reset){ - eof = reset; - err = reset; - if(!reset && fp) clearerr(fp); +void IFile::reset(bool reset) { + eof = reset; + err = reset; + if(!reset && fp) clearerr(fp); #ifdef __PLUMED_HAS_ZLIB - if(!reset && gzfp) gzclearerr(gzFile(gzfp)); + if(!reset && gzfp) gzclearerr(gzFile(gzfp)); #endif - return; -} + return; +} -void IFile::allowIgnoredFields(){ +void IFile::allowIgnoredFields() { ignoreFields=true; } -void IFile::allowNoEOL(){ +void IFile::allowNoEOL() { noEOL=true; } diff --git a/src/tools/IFile.h b/src/tools/IFile.h index 222f4a8ea..2d54338df 100644 --- a/src/tools/IFile.h +++ b/src/tools/IFile.h @@ -25,7 +25,7 @@ #include "FileBase.h" #include <vector> -namespace PLMD{ +namespace PLMD { class Value; @@ -39,9 +39,9 @@ but only for sequential input. See OFile for sequential output. */ class IFile: /// Class identifying a single field for fielded output -public virtual FileBase{ + public virtual FileBase { class Field: - public FieldBase{ + public FieldBase { public: bool read; Field(): read(false) {} @@ -66,7 +66,7 @@ public: IFile(); /// Destructor ~IFile(); -/// Opens the file +/// Opens the file IFile& open(const std::string&name); /// Gets the list of all fields IFile& scanFieldList(std::vector<std::string>&); @@ -76,20 +76,20 @@ public: IFile& scanField(const std::string&,int&); /// Read a string field IFile& scanField(const std::string&,std::string&); -/** - Ends a field-formatted line. + /** + Ends a field-formatted line. -Typically used as -\verbatim - if.scanField("a",a).scanField("b",b).scanField(); -\endverbatim -*/ + Typically used as + \verbatim + if.scanField("a",a).scanField("b",b).scanField(); + \endverbatim + */ IFile& scanField(); /// Get a full line as a string IFile& getline(std::string&); -/// Reset end of file +/// Reset end of file void reset(bool); -/// Check if a field exist +/// Check if a field exist bool FieldExist(const std::string& s); /// Read in a value IFile& scanField(Value* val); diff --git a/src/tools/KernelFunctions.cpp b/src/tools/KernelFunctions.cpp index 43714d9a9..d5da1a387 100644 --- a/src/tools/KernelFunctions.cpp +++ b/src/tools/KernelFunctions.cpp @@ -21,7 +21,7 @@ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ #include "KernelFunctions.h" #include "IFile.h" -#include <iostream> +#include <iostream> #include <cmath> namespace PLMD { @@ -30,21 +30,21 @@ namespace PLMD { /* Functions that are used to construct histograms -Constructing histograms is something you learnt to do relatively early in life. You perform an experiment a number of times, -count the number of times each result comes up and then draw a bar graph that describes how often each of the results came up. -This only works when there are a finite number of possible results. If the result a number between 0 and 1 the bar chart is -less easy to draw as there are as many possible results as there are numbers between zero and one - an infinite number. -To resolve this problem we replace probability, \f$P\f$ with probability density, \f$\pi\f$, and write the probability of getting +Constructing histograms is something you learnt to do relatively early in life. You perform an experiment a number of times, +count the number of times each result comes up and then draw a bar graph that describes how often each of the results came up. +This only works when there are a finite number of possible results. If the result a number between 0 and 1 the bar chart is +less easy to draw as there are as many possible results as there are numbers between zero and one - an infinite number. +To resolve this problem we replace probability, \f$P\f$ with probability density, \f$\pi\f$, and write the probability of getting a number between \f$a\f$ and \f$b\f$ as: \f[ -P = \int_{a}^b \textrm{d}x \pi(x) +P = \int_{a}^b \textrm{d}x \pi(x) \f] -To calculate probability densities from a set of results we use a process called kernel density estimation. +To calculate probability densities from a set of results we use a process called kernel density estimation. Histograms are accumulated by adding up kernel functions, \f$K\f$, with finite spatial extent, that integrate to one. These functions are centered on each of the \f$n\f$-dimensional data points, \f$\mathbf{x}_i\f$. The overall effect of this -is that each result we obtain in our experiments contributes to the probability density in a finite sized region of the space. +is that each result we obtain in our experiments contributes to the probability density in a finite sized region of the space. Expressing all this mathematically in kernel density estimation we write the probability density as: @@ -52,17 +52,17 @@ Expressing all this mathematically in kernel density estimation we write the pro \pi(\mathbf{x}) = \sum_i K\left[ (\mathbf{x} - \mathbf{x}_i)^T \Sigma (\mathbf{x} - \mathbf{x}_i) \right] \f] -where \f$\Sigma\f$ is an \f$n \times n\f$ matrix called the bandwidth that controls the spatial extent of -the kernel. Whenever we accumulate a histogram (e.g. in \ref HISTOGRAM or in \ref METAD) we use this -technique. +where \f$\Sigma\f$ is an \f$n \times n\f$ matrix called the bandwidth that controls the spatial extent of +the kernel. Whenever we accumulate a histogram (e.g. in \ref HISTOGRAM or in \ref METAD) we use this +technique. There is thus some flexibility in the particular function we use for \f$K[\mathbf{r}]\f$ in the above. The following variants are available. <table align=center frame=void width=95%% cellpadding=5%%> -<tr> -<td> TYPE </td> <td> FUNCTION </td> -</tr> <tr> +<tr> +<td> TYPE </td> <td> FUNCTION </td> +</tr> <tr> <td> gaussian </td> <td> \f$f(r) = \frac{1}{(2 \pi)^{n} \sqrt{|\Sigma^{-1}|}} \exp\left(-0.5 r^2 \right)\f$ </td> </tr> <tr> <td> truncated-gaussian </td> <td> \f$f(r) = \frac{1}{(2 \pi)^{n} \sqrt{|\Sigma^{-1}|} \left(\frac{\erf(-6.25/sqrt{2}) - \erf(-6.25/sqrt{2})}{2}\right)^n} \exp\left(-0.5 r^2 \right)\f$ </td> @@ -79,28 +79,28 @@ space which is given by: \f{eqnarray*}{ V &=& | \Sigma^{-1} | \frac{ \pi^{\frac{n}{2}} }{\left( \frac{n}{2} \right)! } \qquad \textrm{for even} \quad n \\ -V &=& | \Sigma^{-1} | \frac{ 2^{\frac{n+1}{2}} \pi^{\frac{n-1}{2}} }{ n!! } +V &=& | \Sigma^{-1} | \frac{ 2^{\frac{n+1}{2}} \pi^{\frac{n-1}{2}} }{ n!! } \f} In \ref METAD the normalization constants are ignored so that the value of the function at \f$r=0\f$ is equal -to one. In addition in \ref METAD we must be able to differentiate the bias in order to get forces. This limits -the kernels we can use in this method. Notice also that Gaussian kernels should have infinite support. When used -with grids, however, they are assumed to only be non-zero over a finite range. The difference between the +to one. In addition in \ref METAD we must be able to differentiate the bias in order to get forces. This limits +the kernels we can use in this method. Notice also that Gaussian kernels should have infinite support. When used +with grids, however, they are assumed to only be non-zero over a finite range. The difference between the truncated-gaussian and regular gaussian is that the trucated gaussian is scaled so that its integral over the grid -is equal to one when it is normalised. The integral of a regular gaussian when it is evaluated on a grid will be -slightly less that one because of the truncation of a function that should have infinite support. +is equal to one when it is normalised. The integral of a regular gaussian when it is evaluated on a grid will be +slightly less that one because of the truncation of a function that should have infinite support. */ //+ENDPLUMEDOC -KernelFunctions::KernelFunctions( const std::string& input, const bool& normed ){ +KernelFunctions::KernelFunctions( const std::string& input, const bool& normed ) { std::vector<std::string> data=Tools::getWords(input); std::string name=data[0]; data.erase(data.begin()); - std::vector<double> at; + std::vector<double> at; bool foundc = Tools::parseVector(data,"CENTER",at); if(!foundc) plumed_merror("failed to find center keyword in definition of kernel"); - std::vector<double> sig; + std::vector<double> sig; bool founds = Tools::parseVector(data,"SIGMA",sig); if(!founds) plumed_merror("failed to find sigma keyword in definition of kernel"); @@ -111,68 +111,68 @@ KernelFunctions::KernelFunctions( const std::string& input, const bool& normed ) if( !multi && center.size()>1 && sig.size()!=center.size() ) plumed_merror("size mismatch between center size and sigma size"); double h; - bool foundh = Tools::parse(data,"HEIGHT",h); + bool foundh = Tools::parse(data,"HEIGHT",h); if( !foundh) h=1.0; setData( at, sig, name, multi, h, normed ); } -KernelFunctions::KernelFunctions( const std::vector<double>& at, const std::vector<double>& sig, const std::string& type, const bool multivariate, const double& w, const bool norm ){ +KernelFunctions::KernelFunctions( const std::vector<double>& at, const std::vector<double>& sig, const std::string& type, const bool multivariate, const double& w, const bool norm ) { setData( at, sig, type, multivariate, w, norm ); } -void KernelFunctions::setData( const std::vector<double>& at, const std::vector<double>& sig, const std::string& type, const bool multivariate, const double& w, const bool norm ){ +void KernelFunctions::setData( const std::vector<double>& at, const std::vector<double>& sig, const std::string& type, const bool multivariate, const double& w, const bool norm ) { - center.resize( at.size() ); for(unsigned i=0;i<at.size();++i) center[i]=at[i]; - width.resize( sig.size() ); for(unsigned i=0;i<sig.size();++i) width[i]=sig[i]; + center.resize( at.size() ); for(unsigned i=0; i<at.size(); ++i) center[i]=at[i]; + width.resize( sig.size() ); for(unsigned i=0; i<sig.size(); ++i) width[i]=sig[i]; diagonal=false; if (multivariate==false ) diagonal=true; // Setup the kernel type - if(type=="GAUSSIAN" || type=="gaussian" || type=="TRUNCATED-GAUSSIAN" || type=="truncated-gaussian" ){ - ktype=gaussian; - } else if(type=="UNIFORM" || type=="uniform"){ - ktype=uniform; - } else if(type=="TRIANGULAR" || type=="triangular"){ - ktype=triangular; + if(type=="GAUSSIAN" || type=="gaussian" || type=="TRUNCATED-GAUSSIAN" || type=="truncated-gaussian" ) { + ktype=gaussian; + } else if(type=="UNIFORM" || type=="uniform") { + ktype=uniform; + } else if(type=="TRIANGULAR" || type=="triangular") { + ktype=triangular; } else { - plumed_merror(type+" is an invalid kernel type\n"); + plumed_merror(type+" is an invalid kernel type\n"); } - if( norm ){ - double det; unsigned ncv=ndim(); - if(diagonal){ - det=1; for(unsigned i=0;i<width.size();++i) det*=width[i]*width[i]; + if( norm ) { + double det; unsigned ncv=ndim(); + if(diagonal) { + det=1; for(unsigned i=0; i<width.size(); ++i) det*=width[i]*width[i]; } else { - Matrix<double> mymatrix( getMatrix() ), myinv( ncv, ncv ); - Invert(mymatrix,myinv); double logd; - logdet( myinv, logd ); - det=std::exp(logd); + Matrix<double> mymatrix( getMatrix() ), myinv( ncv, ncv ); + Invert(mymatrix,myinv); double logd; + logdet( myinv, logd ); + det=std::exp(logd); } double volume; - if( ktype==gaussian ){ - if( type=="GAUSSIAN" || type=="gaussian" ) volume=pow( 2*pi, 0.5*ncv ) * pow( det, 0.5 ); - else { - // This makes it so the gaussian integrates to one over the range over which it has support - const double DP2CUTOFF=sqrt(6.25); - volume=pow( 2*pi, 0.5*ncv ) * pow( det, 0.5 ) * pow( 0.5 * ( erf(DP2CUTOFF) - erf(-DP2CUTOFF) ), ncv); - } - } else if( ktype==uniform || ktype==triangular ){ - if( ncv%2==1 ){ - double dfact=1; - for(unsigned i=1;i<ncv;i+=2) dfact*=static_cast<double>(i); - volume=( pow( pi, (ncv-1)/2 ) ) * ( pow( 2., (ncv+1)/2 ) ) / dfact; - } else { - double fact=1.; - for(unsigned i=1;i<ncv/2;++i) fact*=static_cast<double>(i); - volume=pow( pi,ncv/2 ) / fact; - } - if(ktype==uniform) volume*=det; - else if(ktype==triangular) volume*=det / 3.; + if( ktype==gaussian ) { + if( type=="GAUSSIAN" || type=="gaussian" ) volume=pow( 2*pi, 0.5*ncv ) * pow( det, 0.5 ); + else { + // This makes it so the gaussian integrates to one over the range over which it has support + const double DP2CUTOFF=sqrt(6.25); + volume=pow( 2*pi, 0.5*ncv ) * pow( det, 0.5 ) * pow( 0.5 * ( erf(DP2CUTOFF) - erf(-DP2CUTOFF) ), ncv); + } + } else if( ktype==uniform || ktype==triangular ) { + if( ncv%2==1 ) { + double dfact=1; + for(unsigned i=1; i<ncv; i+=2) dfact*=static_cast<double>(i); + volume=( pow( pi, (ncv-1)/2 ) ) * ( pow( 2., (ncv+1)/2 ) ) / dfact; + } else { + double fact=1.; + for(unsigned i=1; i<ncv/2; ++i) fact*=static_cast<double>(i); + volume=pow( pi,ncv/2 ) / fact; + } + if(ktype==uniform) volume*=det; + else if(ktype==triangular) volume*=det / 3.; } else { - plumed_merror("not a valid kernel type"); - } - height=w / volume; + plumed_merror("not a valid kernel type"); + } + height=w / volume; } else { height=w; } @@ -188,126 +188,126 @@ double KernelFunctions::getCutoff( const double& width ) const { } std::vector<double> KernelFunctions::getContinuousSupport( ) const { - unsigned ncv=ndim(); + unsigned ncv=ndim(); std::vector<double> support( ncv ); - if(diagonal){ - for(unsigned i=0;i<ncv;++i) support[i]=getCutoff(width[i]); + if(diagonal) { + for(unsigned i=0; i<ncv; ++i) support[i]=getCutoff(width[i]); } else { - Matrix<double> mymatrix( getMatrix() ), myinv( ncv,ncv ); - Invert(mymatrix,myinv); - Matrix<double> myautovec(ncv,ncv); std::vector<double> myautoval(ncv); - diagMat(myinv,myautoval,myautovec); - double maxautoval;maxautoval=0.; - unsigned ind_maxautoval; - for (unsigned i=0;i<ncv;i++){ - if(myautoval[i]>maxautoval){maxautoval=myautoval[i];ind_maxautoval=i;} - } - for(unsigned i=0;i<ncv;++i){ - double extent=fabs(sqrt(maxautoval)*myautovec(i,ind_maxautoval)); - support[i]=getCutoff( extent ); - } + Matrix<double> mymatrix( getMatrix() ), myinv( ncv,ncv ); + Invert(mymatrix,myinv); + Matrix<double> myautovec(ncv,ncv); std::vector<double> myautoval(ncv); + diagMat(myinv,myautoval,myautovec); + double maxautoval; maxautoval=0.; + unsigned ind_maxautoval; + for (unsigned i=0; i<ncv; i++) { + if(myautoval[i]>maxautoval) {maxautoval=myautoval[i]; ind_maxautoval=i;} + } + for(unsigned i=0; i<ncv; ++i) { + double extent=fabs(sqrt(maxautoval)*myautovec(i,ind_maxautoval)); + support[i]=getCutoff( extent ); + } } - return support; + return support; } std::vector<unsigned> KernelFunctions::getSupport( const std::vector<double>& dx ) const { plumed_assert( ndim()==dx.size() ); std::vector<unsigned> support( dx.size() ); std::vector<double> vv=getContinuousSupport( ); - for(unsigned i=0;i<dx.size();++i) support[i]=static_cast<unsigned>(ceil( vv[i]/dx[i] )); + for(unsigned i=0; i<dx.size(); ++i) support[i]=static_cast<unsigned>(ceil( vv[i]/dx[i] )); return support; } double KernelFunctions::evaluate( const std::vector<Value*>& pos, std::vector<double>& derivatives, bool usederiv, bool doInt, double lowI_, double uppI_) const { plumed_dbg_assert( pos.size()==ndim() && derivatives.size()==ndim() ); #ifndef NDEBUG - if( usederiv ) plumed_massert( ktype!=uniform, "step function can not be differentiated" ); + if( usederiv ) plumed_massert( ktype!=uniform, "step function can not be differentiated" ); #endif - if(doInt){ + if(doInt) { plumed_dbg_assert(center.size()==1); if(pos[0]->get()<lowI_) pos[0]->set(lowI_); if(pos[0]->get()>uppI_) pos[0]->set(uppI_); } double r2=0; - if(diagonal){ - for(unsigned i=0;i<ndim();++i){ - derivatives[i]=-pos[i]->difference( center[i] ) / width[i]; - r2+=derivatives[i]*derivatives[i]; - derivatives[i] /= width[i]; - } + if(diagonal) { + for(unsigned i=0; i<ndim(); ++i) { + derivatives[i]=-pos[i]->difference( center[i] ) / width[i]; + r2+=derivatives[i]*derivatives[i]; + derivatives[i] /= width[i]; + } } else { - Matrix<double> mymatrix( getMatrix() ); - for(unsigned i=0;i<mymatrix.nrows();++i){ - double dp_i, dp_j; derivatives[i]=0; - dp_i=-pos[i]->difference( center[i] ); - for(unsigned j=0;j<mymatrix.ncols();++j){ - if(i==j) dp_j=dp_i; - else dp_j=-pos[j]->difference( center[j] ); - - derivatives[i]+=mymatrix(i,j)*dp_j; - r2+=dp_i*dp_j*mymatrix(i,j); - } - } + Matrix<double> mymatrix( getMatrix() ); + for(unsigned i=0; i<mymatrix.nrows(); ++i) { + double dp_i, dp_j; derivatives[i]=0; + dp_i=-pos[i]->difference( center[i] ); + for(unsigned j=0; j<mymatrix.ncols(); ++j) { + if(i==j) dp_j=dp_i; + else dp_j=-pos[j]->difference( center[j] ); + + derivatives[i]+=mymatrix(i,j)*dp_j; + r2+=dp_i*dp_j*mymatrix(i,j); + } + } } double kderiv, kval; - if(ktype==gaussian){ - kval=height*std::exp(-0.5*r2); kderiv=-kval; + if(ktype==gaussian) { + kval=height*std::exp(-0.5*r2); kderiv=-kval; } else { - double r=sqrt(r2); - if(ktype==triangular){ - if( r<1.0 ){ - if(r==0) kderiv=0; - kderiv=-1; kval=height*( 1. - fabs(r) ); - } else { - kval=0.; kderiv=0.; - } - } else if(ktype==uniform){ - kderiv=0.; - if(r<1.0) kval=height; - else kval=0; - } else { - plumed_merror("Not a valid kernel type"); - } - kderiv*=height / r ; - } - for(unsigned i=0;i<ndim();++i) derivatives[i]*=kderiv; - if(doInt){ - if((pos[0]->get() <= lowI_ || pos[0]->get() >= uppI_) && usederiv ) for(unsigned i=0;i<ndim();++i)derivatives[i]=0; + double r=sqrt(r2); + if(ktype==triangular) { + if( r<1.0 ) { + if(r==0) kderiv=0; + kderiv=-1; kval=height*( 1. - fabs(r) ); + } else { + kval=0.; kderiv=0.; + } + } else if(ktype==uniform) { + kderiv=0.; + if(r<1.0) kval=height; + else kval=0; + } else { + plumed_merror("Not a valid kernel type"); + } + kderiv*=height / r ; + } + for(unsigned i=0; i<ndim(); ++i) derivatives[i]*=kderiv; + if(doInt) { + if((pos[0]->get() <= lowI_ || pos[0]->get() >= uppI_) && usederiv ) for(unsigned i=0; i<ndim(); ++i)derivatives[i]=0; } return kval; } -KernelFunctions* KernelFunctions::read( IFile* ifile, const std::vector<std::string>& valnames ){ +KernelFunctions* KernelFunctions::read( IFile* ifile, const std::vector<std::string>& valnames ) { std::string sss; ifile->scanField("multivariate",sss); std::vector<double> cc( valnames.size() ), sig; bool multivariate; - if( sss=="false" ){ - multivariate=false; - sig.resize( valnames.size() ); - for(unsigned i=0;i<valnames.size();++i){ - ifile->scanField(valnames[i],cc[i]); - ifile->scanField("sigma_"+valnames[i],sig[i]); - } - } else if( sss=="true" ){ - multivariate=true; - unsigned ncv=valnames.size(); - sig.resize( (ncv*(ncv+1))/2 ); - Matrix<double> upper(ncv,ncv), lower(ncv,ncv); - for(unsigned i=0;i<ncv;++i){ - ifile->scanField(valnames[i],cc[i]); - for(unsigned j=0;j<ncv-i;j++){ ifile->scanField("sigma_" +valnames[j+i] + "_" + valnames[j], lower(j+i,j) ); upper(j,j+i)=lower(j+i,j); } - } - Matrix<double> mymult( ncv, ncv ), invmatrix(ncv,ncv); - mult(lower,upper,mymult); Invert( mymult, invmatrix ); - unsigned k=0; - for(unsigned i=0;i<ncv;i++){ - for(unsigned j=i;j<ncv;j++){ sig[k]=invmatrix(i,j); k++; } - } + if( sss=="false" ) { + multivariate=false; + sig.resize( valnames.size() ); + for(unsigned i=0; i<valnames.size(); ++i) { + ifile->scanField(valnames[i],cc[i]); + ifile->scanField("sigma_"+valnames[i],sig[i]); + } + } else if( sss=="true" ) { + multivariate=true; + unsigned ncv=valnames.size(); + sig.resize( (ncv*(ncv+1))/2 ); + Matrix<double> upper(ncv,ncv), lower(ncv,ncv); + for(unsigned i=0; i<ncv; ++i) { + ifile->scanField(valnames[i],cc[i]); + for(unsigned j=0; j<ncv-i; j++) { ifile->scanField("sigma_" +valnames[j+i] + "_" + valnames[j], lower(j+i,j) ); upper(j,j+i)=lower(j+i,j); } + } + Matrix<double> mymult( ncv, ncv ), invmatrix(ncv,ncv); + mult(lower,upper,mymult); Invert( mymult, invmatrix ); + unsigned k=0; + for(unsigned i=0; i<ncv; i++) { + for(unsigned j=i; j<ncv; j++) { sig[k]=invmatrix(i,j); k++; } + } } else { - plumed_merror("multivariate flag should equal true or false"); - } + plumed_merror("multivariate flag should equal true or false"); + } double h; ifile->scanField("height",h); - return new KernelFunctions( cc, sig, "gaussian", multivariate ,h, false); + return new KernelFunctions( cc, sig, "gaussian", multivariate,h, false); } } diff --git a/src/tools/KernelFunctions.h b/src/tools/KernelFunctions.h index 381b831d5..a7535e0b2 100644 --- a/src/tools/KernelFunctions.h +++ b/src/tools/KernelFunctions.h @@ -42,23 +42,23 @@ private: /// The height of the kernel double height; /// Used to set all the data in the kernel during construction - avoids double coding as this has two constructors - void setData( const std::vector<double>& at, const std::vector<double>& sig, const std::string& type, const bool multivariate ,const double& w, const bool norm ); + void setData( const std::vector<double>& at, const std::vector<double>& sig, const std::string& type, const bool multivariate,const double& w, const bool norm ); /// Convert the width into matrix form Matrix<double> getMatrix() const; public: KernelFunctions( const std::string& input, const bool& normed ); - KernelFunctions( const std::vector<double>& at, const std::vector<double>& sig, const std::string& type, const bool multivariate ,const double& w, const bool norm ); + KernelFunctions( const std::vector<double>& at, const std::vector<double>& sig, const std::string& type, const bool multivariate,const double& w, const bool norm ); /// Get the dimensionality of the kernel unsigned ndim() const; /// Get the cutoff for a kernel double getCutoff( const double& width ) const ; -/// Get the position of the center +/// Get the position of the center std::vector<double> getCenter() const; /// Get the support - std::vector<unsigned> getSupport( const std::vector<double>& dx ) const; + std::vector<unsigned> getSupport( const std::vector<double>& dx ) const; /// get it in continuous form - std::vector<double> getContinuousSupport( ) const; -/// Evaluate the kernel function with constant intervals + std::vector<double> getContinuousSupport( ) const; +/// Evaluate the kernel function with constant intervals double evaluate( const std::vector<Value*>& pos, std::vector<double>& derivatives, bool usederiv=true, bool doInt=false, double lowI_=-1, double uppI_=-1 ) const; /// Read a kernel function from a file static KernelFunctions* read( IFile* ifile, const std::vector<std::string>& valnames ); @@ -66,11 +66,11 @@ public: inline Matrix<double> KernelFunctions::getMatrix() const { - unsigned k=0, ncv=ndim(); Matrix<double> mymatrix(ncv,ncv); - for(unsigned i=0;i<ncv;i++){ - for(unsigned j=i;j<ncv;j++){ - mymatrix(i,j)=mymatrix(j,i)=width[k]; // recompose the full inverse matrix - k++; + unsigned k=0, ncv=ndim(); Matrix<double> mymatrix(ncv,ncv); + for(unsigned i=0; i<ncv; i++) { + for(unsigned j=i; j<ncv; j++) { + mymatrix(i,j)=mymatrix(j,i)=width[k]; // recompose the full inverse matrix + k++; } } return mymatrix; diff --git a/src/tools/Keywords.cpp b/src/tools/Keywords.cpp index d24627805..7b7e36419 100644 --- a/src/tools/Keywords.cpp +++ b/src/tools/Keywords.cpp @@ -24,202 +24,202 @@ #include "Tools.h" #include <iostream> -namespace PLMD{ - -Keywords::KeyType::KeyType( const std::string& type ){ - if( type=="compulsory" ){ - style=compulsory; - } else if( type=="flag" ){ - style=flag; - } else if( type=="optional" ){ - style=optional; - } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ){ - style=atoms; - } else if( type=="hidden" ){ - style=hidden; - } else if( type=="vessel" ){ - style=vessel; +namespace PLMD { + +Keywords::KeyType::KeyType( const std::string& type ) { + if( type=="compulsory" ) { + style=compulsory; + } else if( type=="flag" ) { + style=flag; + } else if( type=="optional" ) { + style=optional; + } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) { + style=atoms; + } else if( type=="hidden" ) { + style=hidden; + } else if( type=="vessel" ) { + style=vessel; } else { - plumed_massert(false,"invalid keyword specifier " + type); - } -} - -void Keywords::KeyType::setStyle( const std::string& type ){ - if( type=="compulsory" ){ - style=compulsory; - } else if( type=="flag" ){ - style=flag; - } else if( type=="optional" ){ - style=optional; - } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ){ - style=atoms; - } else if( type=="hidden" ){ - style=hidden; - } else if( type=="vessel" ){ - style=vessel; + plumed_massert(false,"invalid keyword specifier " + type); + } +} + +void Keywords::KeyType::setStyle( const std::string& type ) { + if( type=="compulsory" ) { + style=compulsory; + } else if( type=="flag" ) { + style=flag; + } else if( type=="optional" ) { + style=optional; + } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) { + style=atoms; + } else if( type=="hidden" ) { + style=hidden; + } else if( type=="vessel" ) { + style=vessel; } else { - plumed_massert(false,"invalid keyword specifier " + type); - } + plumed_massert(false,"invalid keyword specifier " + type); + } } -void Keywords::add( const Keywords& newkeys ){ - newkeys.copyData( keys, reserved_keys, types, allowmultiple, documentation, booldefs, numdefs, atomtags, cnames, ckey, cdocs ); +void Keywords::add( const Keywords& newkeys ) { + newkeys.copyData( keys, reserved_keys, types, allowmultiple, documentation, booldefs, numdefs, atomtags, cnames, ckey, cdocs ); } -void Keywords::copyData( std::vector<std::string>& kk, std::vector<std::string>& rk, std::map<std::string,KeyType>& tt, std::map<std::string,bool>& am, +void Keywords::copyData( std::vector<std::string>& kk, std::vector<std::string>& rk, std::map<std::string,KeyType>& tt, std::map<std::string,bool>& am, std::map<std::string,std::string>& docs, std::map<std::string,bool>& bools, std::map<std::string,std::string>& nums, std::map<std::string,std::string>& atags, std::vector<std::string>& cnam, std::map<std::string,std::string>& ck, std::map<std::string,std::string>& cd ) const { - for(unsigned i=0;i<keys.size();++i){ - std::string thiskey=keys[i]; - for(unsigned j=0;j<kk.size();++j) plumed_massert( thiskey!=kk[j], "keyword " + thiskey + " is in twice" ); - for(unsigned j=0;j<rk.size();++j) plumed_massert( thiskey!=rk[j], "keyword " + thiskey + " is in twice" ); - kk.push_back( thiskey ); - plumed_massert( types.count( thiskey ), "no type data on keyword " + thiskey + " to copy" ); - tt.insert( std::pair<std::string,KeyType>( thiskey,types.find(thiskey)->second) ); - if( (types.find(thiskey)->second).isAtomList() ) atags.insert( std::pair<std::string,std::string>( thiskey,atomtags.find(thiskey)->second) ); - plumed_massert( allowmultiple.count( thiskey ), "no numbered data on keyword " + thiskey + " to copy" ); - am.insert( std::pair<std::string,bool>(thiskey,allowmultiple.find(thiskey)->second) ); - plumed_massert( documentation.count( thiskey ), "no documentation for keyword " + thiskey + " to copy" ); - docs.insert( std::pair<std::string,std::string>(thiskey,documentation.find(thiskey)->second) ); - if( booldefs.count( thiskey ) ) bools.insert( std::pair<std::string,bool>( thiskey,booldefs.find(thiskey)->second) ); - if( numdefs.count( thiskey ) ) nums.insert( std::pair<std::string,std::string>( thiskey,numdefs.find(thiskey)->second) ); - } - for(unsigned i=0;i<reserved_keys.size();++i){ - std::string thiskey=reserved_keys[i]; - for(unsigned j=0;j<kk.size();++j) plumed_massert( thiskey!=kk[j], "keyword " + thiskey + " is in twice" ); - for(unsigned j=0;j<rk.size();++j) plumed_massert( thiskey!=rk[j], "keyword " + thiskey + " is in twice" ); - rk.push_back( thiskey ); - plumed_massert( types.count( thiskey ), "no type data on keyword " + thiskey + " to copy" ); - tt.insert( std::pair<std::string,KeyType>( thiskey,types.find(thiskey)->second) ); - if( (types.find(thiskey)->second).isAtomList() ) atags.insert( std::pair<std::string,std::string>( thiskey,atomtags.find(thiskey)->second) ); - plumed_massert( allowmultiple.count( thiskey ), "no numbered data on keyword " + thiskey + " to copy" ); - am.insert( std::pair<std::string,bool>(thiskey,allowmultiple.find(thiskey)->second) ); - plumed_massert( documentation.count( thiskey ), "no documentation for keyword " + thiskey + " to copy" ); - docs.insert( std::pair<std::string,std::string>(thiskey,documentation.find(thiskey)->second) ); - if( booldefs.count( thiskey ) ) bools.insert( std::pair<std::string,bool>( thiskey,booldefs.find(thiskey)->second) ); - if( numdefs.count( thiskey ) ) nums.insert( std::pair<std::string,std::string>( thiskey,numdefs.find(thiskey)->second) ); - } - for(unsigned i=0;i<cnames.size();++i){ - std::string thisnam=cnames[i]; - for(unsigned j=0;j<cnam.size();++j) plumed_massert( thisnam!=cnam[j], "component " + thisnam + " is in twice" ); - cnam.push_back( thisnam ); - plumed_massert( ckey.count( thisnam ), "no keyword data on component " + thisnam + " to copy" ); - ck.insert( std::pair<std::string,std::string>( thisnam, ckey.find(thisnam)->second) ); - plumed_massert( cdocs.count( thisnam ), "no documentation on component " + thisnam + " to copy" ); - cd.insert( std::pair<std::string,std::string>( thisnam, cdocs.find(thisnam)->second) ); - } -} - -void Keywords::reserve( const std::string & t, const std::string & k, const std::string & d ){ + for(unsigned i=0; i<keys.size(); ++i) { + std::string thiskey=keys[i]; + for(unsigned j=0; j<kk.size(); ++j) plumed_massert( thiskey!=kk[j], "keyword " + thiskey + " is in twice" ); + for(unsigned j=0; j<rk.size(); ++j) plumed_massert( thiskey!=rk[j], "keyword " + thiskey + " is in twice" ); + kk.push_back( thiskey ); + plumed_massert( types.count( thiskey ), "no type data on keyword " + thiskey + " to copy" ); + tt.insert( std::pair<std::string,KeyType>( thiskey,types.find(thiskey)->second) ); + if( (types.find(thiskey)->second).isAtomList() ) atags.insert( std::pair<std::string,std::string>( thiskey,atomtags.find(thiskey)->second) ); + plumed_massert( allowmultiple.count( thiskey ), "no numbered data on keyword " + thiskey + " to copy" ); + am.insert( std::pair<std::string,bool>(thiskey,allowmultiple.find(thiskey)->second) ); + plumed_massert( documentation.count( thiskey ), "no documentation for keyword " + thiskey + " to copy" ); + docs.insert( std::pair<std::string,std::string>(thiskey,documentation.find(thiskey)->second) ); + if( booldefs.count( thiskey ) ) bools.insert( std::pair<std::string,bool>( thiskey,booldefs.find(thiskey)->second) ); + if( numdefs.count( thiskey ) ) nums.insert( std::pair<std::string,std::string>( thiskey,numdefs.find(thiskey)->second) ); + } + for(unsigned i=0; i<reserved_keys.size(); ++i) { + std::string thiskey=reserved_keys[i]; + for(unsigned j=0; j<kk.size(); ++j) plumed_massert( thiskey!=kk[j], "keyword " + thiskey + " is in twice" ); + for(unsigned j=0; j<rk.size(); ++j) plumed_massert( thiskey!=rk[j], "keyword " + thiskey + " is in twice" ); + rk.push_back( thiskey ); + plumed_massert( types.count( thiskey ), "no type data on keyword " + thiskey + " to copy" ); + tt.insert( std::pair<std::string,KeyType>( thiskey,types.find(thiskey)->second) ); + if( (types.find(thiskey)->second).isAtomList() ) atags.insert( std::pair<std::string,std::string>( thiskey,atomtags.find(thiskey)->second) ); + plumed_massert( allowmultiple.count( thiskey ), "no numbered data on keyword " + thiskey + " to copy" ); + am.insert( std::pair<std::string,bool>(thiskey,allowmultiple.find(thiskey)->second) ); + plumed_massert( documentation.count( thiskey ), "no documentation for keyword " + thiskey + " to copy" ); + docs.insert( std::pair<std::string,std::string>(thiskey,documentation.find(thiskey)->second) ); + if( booldefs.count( thiskey ) ) bools.insert( std::pair<std::string,bool>( thiskey,booldefs.find(thiskey)->second) ); + if( numdefs.count( thiskey ) ) nums.insert( std::pair<std::string,std::string>( thiskey,numdefs.find(thiskey)->second) ); + } + for(unsigned i=0; i<cnames.size(); ++i) { + std::string thisnam=cnames[i]; + for(unsigned j=0; j<cnam.size(); ++j) plumed_massert( thisnam!=cnam[j], "component " + thisnam + " is in twice" ); + cnam.push_back( thisnam ); + plumed_massert( ckey.count( thisnam ), "no keyword data on component " + thisnam + " to copy" ); + ck.insert( std::pair<std::string,std::string>( thisnam, ckey.find(thisnam)->second) ); + plumed_massert( cdocs.count( thisnam ), "no documentation on component " + thisnam + " to copy" ); + cd.insert( std::pair<std::string,std::string>( thisnam, cdocs.find(thisnam)->second) ); + } +} + +void Keywords::reserve( const std::string & t, const std::string & k, const std::string & d ) { plumed_assert( !exists(k) && !reserved(k) ); std::string fd, lowkey=k; // Convert to lower case std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),tolower); - // Remove any underscore characters - for(unsigned i=0;;++i){ - std::size_t num=lowkey.find_first_of("_"); - if( num==std::string::npos ) break; - lowkey.erase( lowkey.begin() + num, lowkey.begin() + num + 1 ); - } - if( t=="vessel" ){ - fd = d + " The final value can be referenced using <em>label</em>." + lowkey; - if(d.find("flag")==std::string::npos) fd += ". You can use multiple instances of this keyword i.e. " + - k +"1, " + k + "2, " + k + "3... The corresponding values are then " - "referenced using <em>label</em>."+ lowkey +"-1, <em>label</em>." + lowkey + - "-2, <em>label</em>." + lowkey + "-3..."; - allowmultiple.insert( std::pair<std::string,bool>(k,true) ); - types.insert( std::pair<std::string,KeyType>(k,KeyType("vessel")) ); - } else if( t=="numbered" ){ - fd = d + " You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3..."; - allowmultiple.insert( std::pair<std::string,bool>(k,true) ); - types.insert( std::pair<std::string,KeyType>(k,KeyType("optional")) ); +// Remove any underscore characters + for(unsigned i=0;; ++i) { + std::size_t num=lowkey.find_first_of("_"); + if( num==std::string::npos ) break; + lowkey.erase( lowkey.begin() + num, lowkey.begin() + num + 1 ); + } + if( t=="vessel" ) { + fd = d + " The final value can be referenced using <em>label</em>." + lowkey; + if(d.find("flag")==std::string::npos) fd += ". You can use multiple instances of this keyword i.e. " + + k +"1, " + k + "2, " + k + "3... The corresponding values are then " + "referenced using <em>label</em>."+ lowkey +"-1, <em>label</em>." + lowkey + + "-2, <em>label</em>." + lowkey + "-3..."; + allowmultiple.insert( std::pair<std::string,bool>(k,true) ); + types.insert( std::pair<std::string,KeyType>(k,KeyType("vessel")) ); + } else if( t=="numbered" ) { + fd = d + " You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3..."; + allowmultiple.insert( std::pair<std::string,bool>(k,true) ); + types.insert( std::pair<std::string,KeyType>(k,KeyType("optional")) ); } else { - fd = d; - if( t=="atoms" && isaction ) fd = d + ". For more information on how to specify lists of atoms see \\ref Group"; - allowmultiple.insert( std::pair<std::string,bool>(k,false) ); - types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) ); - if( (types.find(k)->second).isAtomList() ) atomtags.insert( std::pair<std::string,std::string>(k,t) ); + fd = d; + if( t=="atoms" && isaction ) fd = d + ". For more information on how to specify lists of atoms see \\ref Group"; + allowmultiple.insert( std::pair<std::string,bool>(k,false) ); + types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) ); + if( (types.find(k)->second).isAtomList() ) atomtags.insert( std::pair<std::string,std::string>(k,t) ); } - documentation.insert( std::pair<std::string,std::string>(k,fd) ); - reserved_keys.push_back(k); + documentation.insert( std::pair<std::string,std::string>(k,fd) ); + reserved_keys.push_back(k); } -void Keywords::reserveFlag( const std::string & k, const bool def, const std::string & d ){ - plumed_assert( !exists(k) && !reserved(k) ); +void Keywords::reserveFlag( const std::string & k, const bool def, const std::string & d ) { + plumed_assert( !exists(k) && !reserved(k) ); std::string defstr; if( def ) { defstr="( default=on ) "; } else { defstr="( default=off ) "; } types.insert( std::pair<std::string,KeyType>(k,KeyType("flag")) ); std::string fd,lowkey=k; std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),tolower); fd=defstr + d; - documentation.insert( std::pair<std::string,std::string>(k,fd) ); + documentation.insert( std::pair<std::string,std::string>(k,fd) ); allowmultiple.insert( std::pair<std::string,bool>(k,false) ); - booldefs.insert( std::pair<std::string,bool>(k,def) ); - reserved_keys.push_back(k); + booldefs.insert( std::pair<std::string,bool>(k,def) ); + reserved_keys.push_back(k); } -void Keywords::use( const std::string & k ){ +void Keywords::use( const std::string & k ) { plumed_massert( reserved(k), "the " + k + " keyword is not reserved"); - for(unsigned i=0;i<reserved_keys.size();++i){ - if(reserved_keys[i]==k) keys.push_back( reserved_keys[i] ); + for(unsigned i=0; i<reserved_keys.size(); ++i) { + if(reserved_keys[i]==k) keys.push_back( reserved_keys[i] ); } } -void Keywords::reset_style( const std::string & k, const std::string & style ){ +void Keywords::reset_style( const std::string & k, const std::string & style ) { plumed_assert( exists(k) || reserved(k) ); (types.find(k)->second).setStyle(style); - if( (types.find(k)->second).isVessel() ) allowmultiple[k]=true; + if( (types.find(k)->second).isVessel() ) allowmultiple[k]=true; if( (types.find(k)->second).isAtomList() ) atomtags.insert( std::pair<std::string,std::string>(k,style) ); } -void Keywords::add( const std::string & t, const std::string & k, const std::string & d ){ - plumed_massert( !exists(k) && t!="flag" && !reserved(k) && t!="vessel" , "keyword " + k + " has already been registered"); +void Keywords::add( const std::string & t, const std::string & k, const std::string & d ) { + plumed_massert( !exists(k) && t!="flag" && !reserved(k) && t!="vessel", "keyword " + k + " has already been registered"); std::string fd; - if( t=="numbered" ){ - fd=d + " You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3..."; - allowmultiple.insert( std::pair<std::string,bool>(k,true) ); - types.insert( std::pair<std::string,KeyType>(k, KeyType("optional")) ); - } else { - fd=d; - allowmultiple.insert( std::pair<std::string,bool>(k,false) ); - types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) ); - if( (types.find(k)->second).isAtomList() ) atomtags.insert( std::pair<std::string,std::string>(k,t) ); + if( t=="numbered" ) { + fd=d + " You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3..."; + allowmultiple.insert( std::pair<std::string,bool>(k,true) ); + types.insert( std::pair<std::string,KeyType>(k, KeyType("optional")) ); + } else { + fd=d; + allowmultiple.insert( std::pair<std::string,bool>(k,false) ); + types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) ); + if( (types.find(k)->second).isAtomList() ) atomtags.insert( std::pair<std::string,std::string>(k,t) ); } if( t=="atoms" && isaction ) fd = d + ". For more information on how to specify lists of atoms see \\ref Group"; documentation.insert( std::pair<std::string,std::string>(k,fd) ); - keys.push_back(k); + keys.push_back(k); } -void Keywords::add( const std::string & t, const std::string & k, const std::string & def, const std::string & d ){ +void Keywords::add( const std::string & t, const std::string & k, const std::string & def, const std::string & d ) { plumed_assert( !exists(k) && !reserved(k) && (t=="compulsory" || t=="hidden" )); // An optional keyword can't have a default - types.insert( std::pair<std::string,KeyType>(k, KeyType(t)) ); + types.insert( std::pair<std::string,KeyType>(k, KeyType(t)) ); documentation.insert( std::pair<std::string,std::string>(k,"( default=" + def + " ) " + d) ); allowmultiple.insert( std::pair<std::string,bool>(k,false) ); numdefs.insert( std::pair<std::string,std::string>(k,def) ); - keys.push_back(k); -} + keys.push_back(k); +} -void Keywords::addFlag( const std::string & k, const bool def, const std::string & d ){ - plumed_massert( !exists(k) && !reserved(k), "keyword " + k + " has already been registered"); +void Keywords::addFlag( const std::string & k, const bool def, const std::string & d ) { + plumed_massert( !exists(k) && !reserved(k), "keyword " + k + " has already been registered"); std::string defstr; if( def ) { defstr="( default=on ) "; } else { defstr="( default=off ) "; } types.insert( std::pair<std::string,KeyType>(k,KeyType("flag")) ); documentation.insert( std::pair<std::string,std::string>(k,defstr + d) ); allowmultiple.insert( std::pair<std::string,bool>(k,false) ); - booldefs.insert( std::pair<std::string,bool>(k,def) ); - keys.push_back(k); -} + booldefs.insert( std::pair<std::string,bool>(k,def) ); + keys.push_back(k); +} -void Keywords::remove( const std::string & k ){ +void Keywords::remove( const std::string & k ) { bool found=false; unsigned j=0, n=0; - while(true){ - for(j=0;j<keys.size();j++) if(keys[j]==k)break; - for(n=0;n<reserved_keys.size();n++) if(reserved_keys[n]==k)break; - if(j<keys.size()){ + while(true) { + for(j=0; j<keys.size(); j++) if(keys[j]==k)break; + for(n=0; n<reserved_keys.size(); n++) if(reserved_keys[n]==k)break; + if(j<keys.size()) { keys.erase(keys.begin()+j); found=true; - } else if(n<reserved_keys.size()){ + } else if(n<reserved_keys.size()) { reserved_keys.erase(reserved_keys.begin()+n); found=true; } else break; @@ -239,7 +239,7 @@ bool Keywords::style( const std::string & k, const std::string & t ) const { plumed_massert( types.count(k), "Did not find keyword " + k ); if( (types.find(k)->second).toString()==t ) return true; - return false; + return false; } unsigned Keywords::size() const { @@ -252,15 +252,15 @@ std::string Keywords::getKeyword( const unsigned i ) const { } bool Keywords::exists( const std::string & k ) const { - for(unsigned i=0;i<keys.size();++i){ - if( keys[i]==k ) return true; + for(unsigned i=0; i<keys.size(); ++i) { + if( keys[i]==k ) return true; } return false; } bool Keywords::reserved( const std::string & k ) const { - for(unsigned i=0;i<reserved_keys.size();++i){ - if( reserved_keys[i]==k ) return true; + for(unsigned i=0; i<reserved_keys.size(); ++i) { + if( reserved_keys[i]==k ) return true; } return false; } @@ -268,52 +268,52 @@ bool Keywords::reserved( const std::string & k ) const { void Keywords::print_template(const std::string& actionname, bool include_optional) const { unsigned nkeys=0; printf("%s",actionname.c_str()); - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isAtomList() ) nkeys++; + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isAtomList() ) nkeys++; } - if( nkeys>0 ){ + if( nkeys>0 ) { std::string prevtag="start"; - for(unsigned i=0;i<keys.size();++i){ - if( (types.find(keys[i])->second).isAtomList() ){ - plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello"); - if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second ) break; - if( (atomtags.find(keys[i])->second).find("residues")!=std::string::npos) printf(" %s=<residue selection>", keys[i].c_str() ); - else printf(" %s=<atom selection>", keys[i].c_str() ); - prevtag=atomtags.find(keys[i])->second; - } + for(unsigned i=0; i<keys.size(); ++i) { + if( (types.find(keys[i])->second).isAtomList() ) { + plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello"); + if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second ) break; + if( (atomtags.find(keys[i])->second).find("residues")!=std::string::npos) printf(" %s=<residue selection>", keys[i].c_str() ); + else printf(" %s=<atom selection>", keys[i].c_str() ); + prevtag=atomtags.find(keys[i])->second; + } } } nkeys=0; - for(unsigned i=0;i<keys.size();++i){ - if ( include_optional || \ - (types.find(keys[i])->second).isCompulsory() ) nkeys++; - } - if( nkeys>0 ){ - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isCompulsory() ){ - std::string def; - if( getDefaultValue( keys[i], def) ){ - printf(" %s=%s ", keys[i].c_str(), def.c_str() ); - } else { - printf(" %s= ", keys[i].c_str() ); - } - } else if (include_optional) { - // TG no defaults for optional keywords? - printf(" [%s]", keys[i].c_str() ); - } - } + for(unsigned i=0; i<keys.size(); ++i) { + if ( include_optional || \ + (types.find(keys[i])->second).isCompulsory() ) nkeys++; + } + if( nkeys>0 ) { + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isCompulsory() ) { + std::string def; + if( getDefaultValue( keys[i], def) ) { + printf(" %s=%s ", keys[i].c_str(), def.c_str() ); + } else { + printf(" %s= ", keys[i].c_str() ); + } + } else if (include_optional) { + // TG no defaults for optional keywords? + printf(" [%s]", keys[i].c_str() ); + } + } } printf("\n"); } void Keywords::print_vim() const { - for(unsigned i=0;i<keys.size();++i){ - if( (types.find(keys[i])->second).isFlag() ){ - printf( ",flag:%s", keys[i].c_str() ); - } else { - if( allowmultiple.find(keys[i])->second ) printf(",numbered:%s",keys[i].c_str() ); - else printf(",option:%s",keys[i].c_str() ); - } + for(unsigned i=0; i<keys.size(); ++i) { + if( (types.find(keys[i])->second).isFlag() ) { + printf( ",flag:%s", keys[i].c_str() ); + } else { + if( allowmultiple.find(keys[i])->second ) printf(",numbered:%s",keys[i].c_str() ); + else printf(",option:%s",keys[i].c_str() ); + } } fprintf(stdout,"\n"); print(stdout); @@ -322,171 +322,171 @@ void Keywords::print_vim() const { void Keywords::print_html() const { // This is the part that outputs the details of the components - if( cnames.size()>0 ){ - unsigned ndef=0; - for(unsigned i=0;i<cnames.size();++i){ - if(ckey.find(cnames[i])->second=="default") ndef++; - } + if( cnames.size()>0 ) { + unsigned ndef=0; + for(unsigned i=0; i<cnames.size(); ++i) { + if(ckey.find(cnames[i])->second=="default") ndef++; + } - if( ndef>0 ){ - std::cout<<"\\par Description of components\n\n"; - std::cout<<cstring<<"\n\n"; - std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n"; - printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Description </b> </td> </tr>\n"); - unsigned nndef=0; - for(unsigned i=0;i<cnames.size();++i){ - //plumed_assert( ckey.find(cnames[i])->second=="default" ); - if( ckey.find(cnames[i])->second!="default" ){ nndef++; continue; } + if( ndef>0 ) { + std::cout<<"\\par Description of components\n\n"; + std::cout<<cstring<<"\n\n"; + std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n"; + printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Description </b> </td> </tr>\n"); + unsigned nndef=0; + for(unsigned i=0; i<cnames.size(); ++i) { + //plumed_assert( ckey.find(cnames[i])->second=="default" ); + if( ckey.find(cnames[i])->second!="default" ) { nndef++; continue; } + printf("<tr>\n"); + printf("<td width=15%%> <b> %s </b></td>\n",cnames[i].c_str() ); + printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() ); + printf("</tr>\n"); + } + std::cout<<"</table>\n\n"; + if( nndef>0 ) { + std::cout<<"In addition the following quantities can be calculated by employing the keywords listed below"<<std::endl; + std::cout<<"\n\n"; + std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n"; + printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n"); + for(unsigned i=0; i<cnames.size(); ++i) { + if( ckey.find(cnames[i])->second!="default") { printf("<tr>\n"); - printf("<td width=15%%> <b> %s </b></td>\n",cnames[i].c_str() ); + printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n", + cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() ); printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() ); printf("</tr>\n"); - } - std::cout<<"</table>\n\n"; - if( nndef>0 ){ - std::cout<<"In addition the following quantities can be calculated by employing the keywords listed below"<<std::endl; - std::cout<<"\n\n"; - std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n"; - printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n"); - for(unsigned i=0;i<cnames.size();++i){ - if( ckey.find(cnames[i])->second!="default"){ - printf("<tr>\n"); - printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n", - cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() ); - printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() ); - printf("</tr>\n"); - } - } - std::cout<<"</table>\n\n"; - } - } else { - unsigned nregs=0; - for(unsigned i=0;i<cnames.size();++i){ - if( exists(ckey.find(cnames[i])->second) ) nregs++; - } - if( nregs>0 ){ - std::cout<<"\\par Description of components\n\n"; - std::cout<<cstring<<"\n\n"; - std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n"; - printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n"); - for(unsigned i=0;i<cnames.size();++i){ - if( exists(ckey.find(cnames[i])->second) ){ - printf("<tr>\n"); - printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n", - cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() ); - printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() ); - printf("</tr>\n"); - } - } - std::cout<<"</table>\n\n"; - } + } + } + std::cout<<"</table>\n\n"; + } + } else { + unsigned nregs=0; + for(unsigned i=0; i<cnames.size(); ++i) { + if( exists(ckey.find(cnames[i])->second) ) nregs++; + } + if( nregs>0 ) { + std::cout<<"\\par Description of components\n\n"; + std::cout<<cstring<<"\n\n"; + std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n"; + printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n"); + for(unsigned i=0; i<cnames.size(); ++i) { + if( exists(ckey.find(cnames[i])->second) ) { + printf("<tr>\n"); + printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n", + cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() ); + printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() ); + printf("</tr>\n"); + } + } + std::cout<<"</table>\n\n"; } + } } unsigned nkeys=0; - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isAtomList() ) nkeys++; + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isAtomList() ) nkeys++; } - if( nkeys>0 ){ + if( nkeys>0 ) { if(isaction) std::cout<<"\\par The atoms involved can be specified using\n\n"; else std::cout<<"\\par The input trajectory is specified using one of the following\n\n"; std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n"; std::string prevtag="start"; - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isAtomList() ){ - plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello"); - if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second && isaction ){ - std::cout<<"</table>\n\n"; - std::cout<<"\\par Or alternatively by using\n\n"; - std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n"; - } - print_html_item( keys[i] ); - prevtag=atomtags.find(keys[i])->second; + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isAtomList() ) { + plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello"); + if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second && isaction ) { + std::cout<<"</table>\n\n"; + std::cout<<"\\par Or alternatively by using\n\n"; + std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n"; } + print_html_item( keys[i] ); + prevtag=atomtags.find(keys[i])->second; + } } std::cout<<"</table>\n\n"; } nkeys=0; - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isCompulsory() ) nkeys++; - } - if( nkeys>0 ){ - if(isaction) std::cout<< "\\par Compulsory keywords\n\n"; - else std::cout<<"\\par The following must be present\n\n"; - std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n"; - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isCompulsory() ) print_html_item( keys[i] ); - } - std::cout<<"</table>\n\n"; + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isCompulsory() ) nkeys++; + } + if( nkeys>0 ) { + if(isaction) std::cout<< "\\par Compulsory keywords\n\n"; + else std::cout<<"\\par The following must be present\n\n"; + std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n"; + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isCompulsory() ) print_html_item( keys[i] ); + } + std::cout<<"</table>\n\n"; } nkeys=0; - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isFlag() || (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++; - } - if( nkeys>0 ){ - if(isaction) std::cout<<"\\par Options\n\n"; - else std::cout<<"\\par The following options are available\n\n"; - std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n"; - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isFlag() ) print_html_item( keys[i] ); - } - std::cout<<"\n"; + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isFlag() || (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++; + } + if( nkeys>0 ) { + if(isaction) std::cout<<"\\par Options\n\n"; + else std::cout<<"\\par The following options are available\n\n"; + std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n"; + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isFlag() ) print_html_item( keys[i] ); + } + std::cout<<"\n"; } nkeys=0; - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++; + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++; } - if( nkeys>0 ){ - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) print_html_item( keys[i] ); - } - std::cout<<"\n"; + if( nkeys>0 ) { + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) print_html_item( keys[i] ); + } + std::cout<<"\n"; } std::cout<<"</table>\n\n"; } void Keywords::print( FILE* out ) const { unsigned nkeys=0; - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isAtomList() ) nkeys++; + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isAtomList() ) nkeys++; } - if( nkeys>0 ){ - fprintf(out,"The input trajectory can be in any of the following formats: \n\n"); - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isAtomList() ) printKeyword( keys[i], out ); - } + if( nkeys>0 ) { + fprintf(out,"The input trajectory can be in any of the following formats: \n\n"); + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isAtomList() ) printKeyword( keys[i], out ); + } } nkeys=0; - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isCompulsory() ) nkeys++; + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isCompulsory() ) nkeys++; } unsigned ncompulsory=nkeys; - if( nkeys>0 ){ - fprintf(out,"\nThe following arguments are compulsory: \n\n"); - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isCompulsory() ) printKeyword( keys[i], out ); //log.printKeyword( keys[i], documentation[i] ); - } - } - nkeys=0; - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isFlag() ) nkeys++; - } - if( nkeys>0 ){ - if(ncompulsory>0) fprintf( out,"\nIn addition you may use the following options: \n\n"); - else fprintf( out,"\nThe following options are available\n\n"); - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isFlag() ) printKeyword( keys[i], out ); //log.printKeyword( keys[i], documentation[i] ); - } + if( nkeys>0 ) { + fprintf(out,"\nThe following arguments are compulsory: \n\n"); + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isCompulsory() ) printKeyword( keys[i], out ); //log.printKeyword( keys[i], documentation[i] ); + } + } + nkeys=0; + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isFlag() ) nkeys++; + } + if( nkeys>0 ) { + if(ncompulsory>0) fprintf( out,"\nIn addition you may use the following options: \n\n"); + else fprintf( out,"\nThe following options are available\n\n"); + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isFlag() ) printKeyword( keys[i], out ); //log.printKeyword( keys[i], documentation[i] ); + } } nkeys=0; - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++; + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++; } - if( nkeys>0 ){ - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) printKeyword( keys[i], out ); //log.printKeyword( keys[i], documentation[i] ); - } - fprintf(out,"\n"); + if( nkeys>0 ) { + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) printKeyword( keys[i], out ); //log.printKeyword( keys[i], documentation[i] ); + } + fprintf(out,"\n"); } } @@ -495,59 +495,59 @@ void Keywords::printKeyword( const std::string& key, FILE* out ) const { std::vector<std::string> w=Tools::getWords( documentation.find(key)->second ); fprintf(out,"%23s - ", key.c_str() ); unsigned nl=0; std::string blank=" "; - for(unsigned i=0;i<w.size();++i){ - nl+=w[i].length() + 1; - if( nl>60 ){ - fprintf(out,"\n%23s %s ", blank.c_str(), w[i].c_str() ); nl=0; - } else { - fprintf(out,"%s ", w[i].c_str() ); - } - if( killdot && w[i].find(".")!=std::string::npos ) break; // If there is latex only write up to first dot + for(unsigned i=0; i<w.size(); ++i) { + nl+=w[i].length() + 1; + if( nl>60 ) { + fprintf(out,"\n%23s %s ", blank.c_str(), w[i].c_str() ); nl=0; + } else { + fprintf(out,"%s ", w[i].c_str() ); + } + if( killdot && w[i].find(".")!=std::string::npos ) break; // If there is latex only write up to first dot } fprintf(out,"\n"); } void Keywords::print( Log& log ) const { unsigned nkeys=0; - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isAtomList() ) nkeys++; + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isAtomList() ) nkeys++; } - if (nkeys>0 ){ - log.printf( "The input for this keyword can be specified using one of the following \n\n"); - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isAtomList() ) printKeyword( keys[i], log ); //log.printKeyword( keys[i], documentation[i] ); - } + if (nkeys>0 ) { + log.printf( "The input for this keyword can be specified using one of the following \n\n"); + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isAtomList() ) printKeyword( keys[i], log ); //log.printKeyword( keys[i], documentation[i] ); + } } nkeys=0; - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isCompulsory() ) nkeys++; + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isCompulsory() ) nkeys++; } - if( nkeys>0 ){ - log.printf( "\n The compulsory keywords for this action are: \n\n"); - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isCompulsory() ) printKeyword( keys[i], log ); //log.printKeyword( keys[i], documentation[i] ); - } + if( nkeys>0 ) { + log.printf( "\n The compulsory keywords for this action are: \n\n"); + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isCompulsory() ) printKeyword( keys[i], log ); //log.printKeyword( keys[i], documentation[i] ); + } } nkeys=0; - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isFlag() ) nkeys++; + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isFlag() ) nkeys++; } - if( nkeys>0 ){ - log.printf( "\n The following options are available: \n\n"); - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isFlag() ) printKeyword( keys[i], log ); //log.printKeyword( keys[i], documentation[i] ); - } - log.printf("\n"); + if( nkeys>0 ) { + log.printf( "\n The following options are available: \n\n"); + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isFlag() ) printKeyword( keys[i], log ); //log.printKeyword( keys[i], documentation[i] ); + } + log.printf("\n"); } nkeys=0; - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isOptional() ) nkeys++; + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isOptional() ) nkeys++; } - if( nkeys>0 ){ - for(unsigned i=0;i<keys.size();++i){ - if ( (types.find(keys[i])->second).isOptional() ) printKeyword( keys[i], log ); //log.printKeyword( keys[i], documentation[i] ); - } - log.printf("\n"); + if( nkeys>0 ) { + for(unsigned i=0; i<keys.size(); ++i) { + if ( (types.find(keys[i])->second).isOptional() ) printKeyword( keys[i], log ); //log.printKeyword( keys[i], documentation[i] ); + } + log.printf("\n"); } } @@ -556,14 +556,14 @@ void Keywords::printKeyword( const std::string& key, Log& log ) const { std::vector<std::string> w=Tools::getWords( documentation.find(key)->second ); log.printf("%23s - ", key.c_str() ); unsigned nl=0; std::string blank=" "; - for(unsigned i=0;i<w.size();++i){ - nl+=w[i].length() + 1; - if( nl>60 ){ - log.printf("\n%23s %s ", blank.c_str(), w[i].c_str() ); nl=0; - } else { - log.printf("%s ", w[i].c_str() ); - } - if( killdot && w[i].find(".")!=std::string::npos ) break; // If there is latex only write up to first dot + for(unsigned i=0; i<w.size(); ++i) { + nl+=w[i].length() + 1; + if( nl>60 ) { + log.printf("\n%23s %s ", blank.c_str(), w[i].c_str() ); nl=0; + } else { + log.printf("%s ", w[i].c_str() ); + } + if( killdot && w[i].find(".")!=std::string::npos ) break; // If there is latex only write up to first dot } log.printf("\n"); } @@ -581,42 +581,42 @@ std::string Keywords::get( const unsigned k ) const { } bool Keywords::getLogicalDefault( std::string key, bool& def ) const { - if( booldefs.find(key)!=booldefs.end() ){ - def=booldefs.find(key)->second; - return true; - } else { - return false; - } + if( booldefs.find(key)!=booldefs.end() ) { + def=booldefs.find(key)->second; + return true; + } else { + return false; + } } bool Keywords::getDefaultValue( std::string key, std::string& def ) const { - plumed_assert( style(key,"compulsory") || style(key,"hidden") ); + plumed_assert( style(key,"compulsory") || style(key,"hidden") ); - if( numdefs.find(key)!=numdefs.end() ){ - def=numdefs.find(key)->second; - return true; - } else { - return false; - } + if( numdefs.find(key)!=numdefs.end() ) { + def=numdefs.find(key)->second; + return true; + } else { + return false; + } } -void Keywords::destroyData(){ - keys.clear(); reserved_keys.clear(); types.clear(); - allowmultiple.clear(); documentation.clear(); - booldefs.clear(); numdefs.clear(); atomtags.clear(); - ckey.clear(); cdocs.clear(); ckey.clear(); +void Keywords::destroyData() { + keys.clear(); reserved_keys.clear(); types.clear(); + allowmultiple.clear(); documentation.clear(); + booldefs.clear(); numdefs.clear(); atomtags.clear(); + ckey.clear(); cdocs.clear(); ckey.clear(); } -void Keywords::setComponentsIntroduction( const std::string& instr ){ +void Keywords::setComponentsIntroduction( const std::string& instr ) { cstring = instr; } -void Keywords::addOutputComponent( const std::string& name, const std::string& key, const std::string& descr ){ +void Keywords::addOutputComponent( const std::string& name, const std::string& key, const std::string& descr ) { plumed_assert( !outputComponentExists( name, false ) ); plumed_massert( name.find("-")==std::string::npos,"dash is reseved character in component names" ); std::size_t num2=name.find_first_of("_"); - if( num2!=std::string::npos ) plumed_massert( num2==0, "underscore is reserved character in component names that has special meaning"); + if( num2!=std::string::npos ) plumed_massert( num2==0, "underscore is reserved character in component names that has special meaning"); ckey.insert( std::pair<std::string,std::string>(name,key) ); cdocs.insert( std::pair<std::string,std::string>(name,descr) ); @@ -629,15 +629,15 @@ bool Keywords::outputComponentExists( const std::string& name, const bool& custo std::string sname; std::size_t num=name.find_first_of("-"); if( num!=std::string::npos ) sname=name.substr(0,num); else { - std::size_t num2=name.find_first_of("_"); - if( num2!=std::string::npos ) sname=name.substr(num2); - else sname=name; + std::size_t num2=name.find_first_of("_"); + if( num2!=std::string::npos ) sname=name.substr(num2); + else sname=name; } - for(unsigned i=0;i<cnames.size();++i){ - if( sname==cnames[i] ) return true; - } + for(unsigned i=0; i<cnames.size(); ++i) { + if( sname==cnames[i] ) return true; + } return false; -} +} } diff --git a/src/tools/Keywords.h b/src/tools/Keywords.h index 2b9001128..7da2155f5 100644 --- a/src/tools/Keywords.h +++ b/src/tools/Keywords.h @@ -28,14 +28,14 @@ #include "Exception.h" -namespace PLMD{ +namespace PLMD { class Log; /// This class holds the keywords and their documentation -class Keywords{ +class Keywords { /// This class lets me pass keyword types easily - class KeyType{ + class KeyType { public: enum {hidden,compulsory,flag,optional,atoms,vessel} style; explicit KeyType( const std::string& type ); @@ -56,7 +56,7 @@ class Keywords{ return ""; } }; -friend class Action; + friend class Action; private: /// Is this an action or driver (this bool affects what style==atoms does in print) bool isaction; @@ -71,7 +71,7 @@ private: /// The documentation for the keywords std::map<std::string,std::string> documentation; /// The default values for the flags (are they on or of) - std::map<std::string,bool> booldefs; + std::map<std::string,bool> booldefs; /// The default values (if there are default values) for compulsory keywords std::map<std::string,std::string> numdefs; /// The tags for atoms - we use this so the manual can differentiate between different ways of specifying atoms @@ -94,12 +94,12 @@ public: /// Constructor Keywords() : isaction(true) {} /// - void isDriver(){ isaction=false; } + void isDriver() { isaction=false; } /// find out whether flag key is on or off by default. bool getLogicalDefault( std::string key, bool& def ) const ; /// Get the value of the default for the keyword named key bool getDefaultValue( std::string key, std::string& def ) const ; -/// Return the number of defined keywords +/// Return the number of defined keywords unsigned size() const; /// Check if numbered keywords are allowed for this action bool numbered( const std::string & k ) const ; @@ -109,7 +109,7 @@ public: void print( Log& log ) const ; /// Print the documentation to a file (use by PLUMED::CLTool::readCommandLineArgs) void print( FILE* out ) const ; -/// Reserve a keyword +/// Reserve a keyword void reserve( const std::string & t, const std::string & k, const std::string & d ); /// Reserve a flag void reserveFlag( const std::string & k, const bool def, const std::string & d ); @@ -143,9 +143,9 @@ public: void add( const Keywords& keys ); /// Copy the keywords data void copyData( std::vector<std::string>& kk, std::vector<std::string>& rk, std::map<std::string,KeyType>& tt, std::map<std::string,bool>& am, - std::map<std::string,std::string>& docs, std::map<std::string,bool>& bools, std::map<std::string,std::string>& nums, - std::map<std::string,std::string>& atags, std::vector<std::string>& cnam, std::map<std::string,std::string>& ck, - std::map<std::string,std::string>& cd ) const ; + std::map<std::string,std::string>& docs, std::map<std::string,bool>& bools, std::map<std::string,std::string>& nums, + std::map<std::string,std::string>& atags, std::vector<std::string>& cnam, std::map<std::string,std::string>& ck, + std::map<std::string,std::string>& cd ) const ; /// Clear everything from the keywords object void destroyData(); /// Set the text that introduces how the components for this action are introduced diff --git a/src/tools/LatticeReduction.cpp b/src/tools/LatticeReduction.cpp index e8658025d..c0bc6b1d0 100644 --- a/src/tools/LatticeReduction.cpp +++ b/src/tools/LatticeReduction.cpp @@ -23,26 +23,26 @@ #include "Exception.h" #include <cstdio> -namespace PLMD{ +namespace PLMD { using namespace std; const double epsilon=1e-14; -void LatticeReduction::sort(Vector v[3]){ +void LatticeReduction::sort(Vector v[3]) { const double onePlusEpsilon=(1.0+epsilon); - for(int i=0;i<3;i++) for(int j=i+1;j<3;j++) if(modulo2(v[i])>modulo2(v[j])){ - Vector x=v[i]; v[i]=v[j]; v[j]=x; - } - for(int i=0;i<2;i++) plumed_assert(modulo2(v[i])<=modulo2(v[i+1])*onePlusEpsilon); + for(int i=0; i<3; i++) for(int j=i+1; j<3; j++) if(modulo2(v[i])>modulo2(v[j])) { + Vector x=v[i]; v[i]=v[j]; v[j]=x; + } + for(int i=0; i<2; i++) plumed_assert(modulo2(v[i])<=modulo2(v[i+1])*onePlusEpsilon); } -void LatticeReduction::reduce(Vector&a,Vector&b){ +void LatticeReduction::reduce(Vector&a,Vector&b) { double ma=modulo2(a); double mb=modulo2(b); unsigned counter=0; - while(true){ - if(mb>ma){ + while(true) { + if(mb>ma) { Vector t(a); a=b; b=t; double mt(ma); ma=mb; mb=mt; } @@ -56,16 +56,16 @@ void LatticeReduction::reduce(Vector&a,Vector&b){ Vector t(a); a=b; b=t; } -void LatticeReduction::reduce2(Vector&a,Vector&b,Vector&c){ +void LatticeReduction::reduce2(Vector&a,Vector&b,Vector&c) { Vector v[3]; v[0]=a; v[1]=b; v[2]=c; int iter=0; int ok=0; - while(ok<3){ + while(ok<3) { int i,j; - if(iter%3==0){ + if(iter%3==0) { i=0; j=1; - } else if(iter%3==1){ + } else if(iter%3==1) { i=0; j=2; } else { i=1; j=2; @@ -80,15 +80,15 @@ void LatticeReduction::reduce2(Vector&a,Vector&b,Vector&c){ a=v[0]; b=v[1]; c=v[2]; } -bool LatticeReduction::isReduced(const Vector&a,const Vector&b){ +bool LatticeReduction::isReduced(const Vector&a,const Vector&b) { const int cut=5; - for(int i=-cut;i<=cut;i++){ + for(int i=-cut; i<=cut; i++) { if(modulo2(b+i*a)<modulo2(b)) return false; } return modulo2(a)<=modulo2(b) && 2.0*dotProduct(a,b)<=modulo2(a); } -void LatticeReduction::reduce2(Tensor&t){ +void LatticeReduction::reduce2(Tensor&t) { Vector a=t.getRow(0); Vector b=t.getRow(1); Vector c=t.getRow(2); @@ -98,17 +98,17 @@ void LatticeReduction::reduce2(Tensor&t){ t.setRow(2,c); } -void LatticeReduction::reduce(Tensor&t){ +void LatticeReduction::reduce(Tensor&t) { reduceFast(t); } -void LatticeReduction::reduceFast(Tensor&t){ +void LatticeReduction::reduceFast(Tensor&t) { Vector v[3]; v[0]=t.getRow(0); v[1]=t.getRow(1); v[2]=t.getRow(2); unsigned counter=0; - while(true){ + while(true) { sort(v); reduce(v[0],v[1]); double b11=modulo2(v[0]); @@ -126,16 +126,16 @@ void LatticeReduction::reduceFast(Tensor&t){ bool first=true; double mbest,mtrial; Vector trial,best; - for(int x1=x1min;x1<=x1max;x1++) - for(int x2=x2min;x2<=x2max;x2++){ - trial=v[2]+x2*v[1]+x1*v[0]; - mtrial=modulo2(trial); - if(first || mtrial<mbest){ - mbest=mtrial; - best=trial; - first=false; + for(int x1=x1min; x1<=x1max; x1++) + for(int x2=x2min; x2<=x2max; x2++) { + trial=v[2]+x2*v[1]+x1*v[0]; + mtrial=modulo2(trial); + if(first || mtrial<mbest) { + mbest=mtrial; + best=trial; + first=false; + } } - } if(modulo2(best)+epsilon>=modulo2(v[2])) break; counter++; if(counter%10000==0) fprintf(stderr,"WARNING: LatticeReduction::reduceFast stuck after %u iterations\n",counter); @@ -148,7 +148,7 @@ void LatticeReduction::reduceFast(Tensor&t){ } -void LatticeReduction::reduceSlow(Tensor&t){ +void LatticeReduction::reduceSlow(Tensor&t) { Vector v[3]; v[0]=t.getRow(0); v[1]=t.getRow(1); @@ -157,14 +157,14 @@ void LatticeReduction::reduceSlow(Tensor&t){ double e01=dotProduct(v[0],v[1]); double e02=dotProduct(v[0],v[2]); double e12=dotProduct(v[1],v[2]); - if(e01*e02*e12<0){ + if(e01*e02*e12<0) { int eps01=0; if(e01>0.0) eps01=1; else if(e01<0.0) eps01=-1; int eps02=0; if(e02>0.0) eps02=1; else if(e02<0.0) eps02=-1; Vector n=v[0]-eps01*v[1]-eps02*v[2]; int i=0; double mx=modulo2(v[i]); - for(int j=1;j<3;j++){ + for(int j=1; j<3; j++) { double f=modulo2(v[j]); - if(f>mx){ + if(f>mx) { i=j; mx=f; } @@ -177,23 +177,23 @@ void LatticeReduction::reduceSlow(Tensor&t){ t.setRow(2,v[2]); } -bool LatticeReduction::isReduced2(const Vector&a,const Vector&b,const Vector &c){ +bool LatticeReduction::isReduced2(const Vector&a,const Vector&b,const Vector &c) { return isReduced(a,b) && isReduced(a,b) && isReduced(b,c); } -bool LatticeReduction::isReduced(const Tensor&t){ +bool LatticeReduction::isReduced(const Tensor&t) { Vector v[3]; double m[3]; v[0]=t.getRow(0); v[1]=t.getRow(1); v[2]=t.getRow(2); - for(int i=0;i<3;i++) m[i]=modulo2(v[i]); + for(int i=0; i<3; i++) m[i]=modulo2(v[i]); if(!((m[0]<=m[1]) && m[1]<=m[2])) return false; const int cut=5; - for(int i=-cut;i<=cut;i++){ + for(int i=-cut; i<=cut; i++) { double mm=modulo2(v[1]+i*v[0]); if(mm<m[1]) return false; - for(int j=-cut;j<=cut;j++){ + for(int j=-cut; j<=cut; j++) { double mx=modulo2(v[2]+i*v[1]+j*v[0]); if(mx<m[2])return false; } diff --git a/src/tools/LatticeReduction.h b/src/tools/LatticeReduction.h index 61ffbe75d..16d999a9c 100644 --- a/src/tools/LatticeReduction.h +++ b/src/tools/LatticeReduction.h @@ -25,16 +25,16 @@ #include "Vector.h" #include "Tensor.h" -namespace PLMD{ +namespace PLMD { /** Class implementing algorithms for lattice reduction. -This class implements algorithms described in +This class implements algorithms described in Igor Semaev, A 3-Dimensional Lattice Reduction Algorithm, CaLC 2001, LNCS 2146, pp. 181–193, 2001. It just collect static methods in a separate namespace. */ -class LatticeReduction{ +class LatticeReduction { /// Gaussian reduction static void reduce(Vector&a,Vector&b); /// Obtain three reduce-2 vectors (Algorithm 1 in the paper), equivalent to reduce2(Tensor&t) diff --git a/src/tools/LinkCells.cpp b/src/tools/LinkCells.cpp index e7f7ec15f..324e0f803 100644 --- a/src/tools/LinkCells.cpp +++ b/src/tools/LinkCells.cpp @@ -23,18 +23,18 @@ #include "Communicator.h" #include "Tools.h" -namespace PLMD{ +namespace PLMD { LinkCells::LinkCells( Communicator& cc ) : -comm(cc), -cutoffwasset(false), -link_cutoff(0.0), -ncells(3), -nstride(3) + comm(cc), + cutoffwasset(false), + link_cutoff(0.0), + ncells(3), + nstride(3) { } -void LinkCells::setCutoff( const double& lcut ){ +void LinkCells::setCutoff( const double& lcut ) { cutoffwasset=true; link_cutoff=lcut; } @@ -42,7 +42,7 @@ double LinkCells::getCutoff() const { plumed_assert( cutoffwasset ); return link_cutoff; } -void LinkCells::buildCellLists( const std::vector<Vector>& pos, const std::vector<unsigned>& indices, const Pbc& pbc ){ +void LinkCells::buildCellLists( const std::vector<Vector>& pos, const std::vector<unsigned>& indices, const Pbc& pbc ) { plumed_assert( cutoffwasset && pos.size()==indices.size() ); // Must be able to check that pbcs are not nonsensical in some way?? -- GAT @@ -51,54 +51,54 @@ void LinkCells::buildCellLists( const std::vector<Vector>& pos, const std::vecto mypbc.setBox( pbc.getBox() ); // Setup the lists - if( pos.size()!=allcells.size() ){ - allcells.resize( pos.size() ); lcell_lists.resize( pos.size() ); + if( pos.size()!=allcells.size() ) { + allcells.resize( pos.size() ); lcell_lists.resize( pos.size() ); } - { + { // This is the reciprocal lattice // notice that reciprocal.getRow(0) is a vector that is orthogonal to b and c // This allows to use linked cells in non orthorhomic boxes - Tensor reciprocal(transpose(mypbc.getInvBox())); - ncells[0] = std::floor( 1.0/ reciprocal.getRow(0).modulo() / link_cutoff ); - if( ncells[0]==0 ) ncells[0]=1; - ncells[1] = std::floor( 1.0/ reciprocal.getRow(1).modulo() / link_cutoff ); - if( ncells[1]==0 ) ncells[1]=1; - ncells[2] = std::floor( 1.0/ reciprocal.getRow(2).modulo() / link_cutoff ); - if( ncells[2]==0 ) ncells[2]=1; + Tensor reciprocal(transpose(mypbc.getInvBox())); + ncells[0] = std::floor( 1.0/ reciprocal.getRow(0).modulo() / link_cutoff ); + if( ncells[0]==0 ) ncells[0]=1; + ncells[1] = std::floor( 1.0/ reciprocal.getRow(1).modulo() / link_cutoff ); + if( ncells[1]==0 ) ncells[1]=1; + ncells[2] = std::floor( 1.0/ reciprocal.getRow(2).modulo() / link_cutoff ); + if( ncells[2]==0 ) ncells[2]=1; } // Setup the strides nstride[0]=1; nstride[1]=ncells[0]; nstride[2]=ncells[0]*ncells[1]; // Setup the storage for link cells unsigned ncellstot=ncells[0]*ncells[1]*ncells[2]; - if( lcell_tots.size()!=ncellstot ){ - lcell_tots.resize( ncellstot ); lcell_starts.resize( ncellstot ); + if( lcell_tots.size()!=ncellstot ) { + lcell_tots.resize( ncellstot ); lcell_starts.resize( ncellstot ); } // Clear nlcells - for(unsigned i=0;i<ncellstot;++i) lcell_tots[i]=0; + for(unsigned i=0; i<ncellstot; ++i) lcell_tots[i]=0; // Clear allcells allcells.assign( allcells.size(), 0 ); // Find out what cell everyone is in unsigned rank=comm.Get_rank(), size=comm.Get_size(); - for(unsigned i=rank;i<pos.size();i+=size){ - allcells[i]=findCell( pos[i] ); - lcell_tots[allcells[i]]++; + for(unsigned i=rank; i<pos.size(); i+=size) { + allcells[i]=findCell( pos[i] ); + lcell_tots[allcells[i]]++; } // And gather all this information on every node comm.Sum( allcells ); comm.Sum( lcell_tots ); // Now prepare the link cell lists unsigned tot=0; - for(unsigned i=0;i<lcell_tots.size();++i){ lcell_starts[i]=tot; tot+=lcell_tots[i]; lcell_tots[i]=0; } + for(unsigned i=0; i<lcell_tots.size(); ++i) { lcell_starts[i]=tot; tot+=lcell_tots[i]; lcell_tots[i]=0; } plumed_assert( tot==pos.size() ); // And setup the link cells properly - for(unsigned j=0;j<pos.size();++j){ - unsigned myind = lcell_starts[ allcells[j] ] + lcell_tots[ allcells[j] ]; - lcell_lists[ myind ] = indices[j]; - lcell_tots[allcells[j]]++; + for(unsigned j=0; j<pos.size(); ++j) { + unsigned myind = lcell_starts[ allcells[j] ] + lcell_tots[ allcells[j] ]; + lcell_lists[ myind ] = indices[j]; + lcell_tots[allcells[j]]++; } } @@ -110,34 +110,34 @@ void LinkCells::retrieveNeighboringAtoms( const Vector& pos, unsigned& natomsper plumed_assert( natomsper==1 || natomsper==2 ); // This is really a bug. If you are trying to reuse this ask GAT for help std::vector<unsigned> celn( findMyCell( pos ) ); - for(int nx=LINKC_MIN(ncells[0]);nx<LINKC_MAX(ncells[0]);++nx){ - int xval = celn[0] + nx; - xval=LINKC_PBC(xval,ncells[0])*nstride[0]; - for(int ny=LINKC_MIN(ncells[1]);ny<LINKC_MAX(ncells[1]);++ny){ - int yval = celn[1] + ny; - yval=LINKC_PBC(yval,ncells[1])*nstride[1]; - for(int nz=LINKC_MIN(ncells[2]);nz<LINKC_MAX(ncells[2]);++nz){ - int zval = celn[2] + nz; - zval=LINKC_PBC(zval,ncells[2])*nstride[2]; - - unsigned mybox=xval+yval+zval; - for(unsigned k=0;k<lcell_tots[mybox];++k){ - unsigned myatom = lcell_lists[lcell_starts[mybox]+k]; - if( myatom!=atoms[0] ){ // Ideally would provide an option to not do this - atoms[natomsper]=myatom; - natomsper++; - } - } - } - } + for(int nx=LINKC_MIN(ncells[0]); nx<LINKC_MAX(ncells[0]); ++nx) { + int xval = celn[0] + nx; + xval=LINKC_PBC(xval,ncells[0])*nstride[0]; + for(int ny=LINKC_MIN(ncells[1]); ny<LINKC_MAX(ncells[1]); ++ny) { + int yval = celn[1] + ny; + yval=LINKC_PBC(yval,ncells[1])*nstride[1]; + for(int nz=LINKC_MIN(ncells[2]); nz<LINKC_MAX(ncells[2]); ++nz) { + int zval = celn[2] + nz; + zval=LINKC_PBC(zval,ncells[2])*nstride[2]; + + unsigned mybox=xval+yval+zval; + for(unsigned k=0; k<lcell_tots[mybox]; ++k) { + unsigned myatom = lcell_lists[lcell_starts[mybox]+k]; + if( myatom!=atoms[0] ) { // Ideally would provide an option to not do this + atoms[natomsper]=myatom; + natomsper++; + } + } + } + } } } std::vector<unsigned> LinkCells::findMyCell( const Vector& pos ) const { Vector fpos=mypbc.realToScaled( pos ); std::vector<unsigned> celn(3); - for(unsigned j=0;j<3;++j){ - celn[j] = std::floor( ( Tools::pbc(fpos[j]) + 0.5 ) * ncells[j] ); - plumed_assert( celn[j]>=0 && celn[j]<ncells[j] ); // Check that atom is in box + for(unsigned j=0; j<3; ++j) { + celn[j] = std::floor( ( Tools::pbc(fpos[j]) + 0.5 ) * ncells[j] ); + plumed_assert( celn[j]>=0 && celn[j]<ncells[j] ); // Check that atom is in box } return celn; } diff --git a/src/tools/LinkCells.h b/src/tools/LinkCells.h index 684059431..b493dbf87 100644 --- a/src/tools/LinkCells.h +++ b/src/tools/LinkCells.h @@ -26,7 +26,7 @@ #include "Vector.h" #include "Pbc.h" -namespace PLMD{ +namespace PLMD { class Communicator; @@ -70,7 +70,7 @@ public: /// Build the link cell lists void buildCellLists( const std::vector<Vector>& pos, const std::vector<unsigned>& indices, const Pbc& pbc ); /// Find a list of relevant atoms - void retrieveNeighboringAtoms( const Vector& pos, unsigned& natomsper, std::vector<unsigned>& atoms ) const ; + void retrieveNeighboringAtoms( const Vector& pos, unsigned& natomsper, std::vector<unsigned>& atoms ) const ; }; inline diff --git a/src/tools/Log.h b/src/tools/Log.h index c0a378fe6..c25ca3f38 100644 --- a/src/tools/Log.h +++ b/src/tools/Log.h @@ -24,7 +24,7 @@ #include "OFile.h" -namespace PLMD{ +namespace PLMD { /// Class containing the log stream. /// diff --git a/src/tools/LoopUnroller.h b/src/tools/LoopUnroller.h index 87e8f5298..83f33ed70 100644 --- a/src/tools/LoopUnroller.h +++ b/src/tools/LoopUnroller.h @@ -22,7 +22,7 @@ #ifndef __PLUMED_tools_LoopUnroller_h #define __PLUMED_tools_LoopUnroller_h -namespace PLMD{ +namespace PLMD { /** \ingroup TOOLBOX @@ -48,7 +48,7 @@ Here xxx is any of the methods of the class. */ template<unsigned n> -class LoopUnroller{ +class LoopUnroller { public: /// Set to zero. /// Same as `for(unsigned i=0;i<n;i++) d[i]=0.0;` @@ -74,84 +74,84 @@ public: }; template<unsigned n> -void LoopUnroller<n>::_zero(double*d){ +void LoopUnroller<n>::_zero(double*d) { LoopUnroller<n-1>::_zero(d); d[n-1]=0.0; } template<> inline -void LoopUnroller<1>::_zero(double*d){ +void LoopUnroller<1>::_zero(double*d) { d[0]=0.0; } template<unsigned n> -void LoopUnroller<n>::_add(double*d,const double*a){ +void LoopUnroller<n>::_add(double*d,const double*a) { LoopUnroller<n-1>::_add(d,a); d[n-1]+=a[n-1]; } template<> inline -void LoopUnroller<1>::_add(double*d,const double*a){ +void LoopUnroller<1>::_add(double*d,const double*a) { d[0]+=a[0]; } template<unsigned n> -void LoopUnroller<n>::_sub(double*d,const double*a){ +void LoopUnroller<n>::_sub(double*d,const double*a) { LoopUnroller<n-1>::_sub(d,a); d[n-1]-=a[n-1]; } template<> inline -void LoopUnroller<1>::_sub(double*d,const double*a){ +void LoopUnroller<1>::_sub(double*d,const double*a) { d[0]-=a[0]; } template<unsigned n> -void LoopUnroller<n>::_mul(double*d,const double s){ +void LoopUnroller<n>::_mul(double*d,const double s) { LoopUnroller<n-1>::_mul(d,s); d[n-1]*=s; } template<> inline -void LoopUnroller<1>::_mul(double*d,const double s){ +void LoopUnroller<1>::_mul(double*d,const double s) { d[0]*=s; } template<unsigned n> -void LoopUnroller<n>::_neg(double*d,const double*a ){ +void LoopUnroller<n>::_neg(double*d,const double*a ) { LoopUnroller<n-1>::_neg(d,a); d[n-1]=-a[n-1]; } template<> inline -void LoopUnroller<1>::_neg(double*d,const double*a){ +void LoopUnroller<1>::_neg(double*d,const double*a) { d[0]=-a[0]; } template<unsigned n> -double LoopUnroller<n>::_sum2(const double*d){ +double LoopUnroller<n>::_sum2(const double*d) { return LoopUnroller<n-1>::_sum2(d)+d[n-1]*d[n-1]; } template<> inline -double LoopUnroller<1>::_sum2(const double*d){ +double LoopUnroller<1>::_sum2(const double*d) { return d[0]*d[0]; } template<unsigned n> -double LoopUnroller<n>::_dot(const double*d,const double*v){ +double LoopUnroller<n>::_dot(const double*d,const double*v) { return LoopUnroller<n-1>::_dot(d,v)+d[n-1]*v[n-1]; } template<> inline -double LoopUnroller<1>::_dot(const double*d,const double*v){ +double LoopUnroller<1>::_dot(const double*d,const double*v) { return d[0]*v[0]; } diff --git a/src/tools/Matrix.h b/src/tools/Matrix.h index 1bfc5ee1b..fd1e35d6d 100644 --- a/src/tools/Matrix.h +++ b/src/tools/Matrix.h @@ -31,234 +31,234 @@ #include "Log.h" #include "lapack/lapack.h" -namespace PLMD{ +namespace PLMD { -/// Calculate the dot product between two vectors -template <typename T> T dotProduct( const std::vector<T>& A, const std::vector<T>& B ){ - plumed_assert( A.size()==B.size() ); - T val; for(unsigned i=0;i<A.size();++i){ val+=A[i]*B[i]; } - return val; +/// Calculate the dot product between two vectors +template <typename T> T dotProduct( const std::vector<T>& A, const std::vector<T>& B ) { + plumed_assert( A.size()==B.size() ); + T val; for(unsigned i=0; i<A.size(); ++i) { val+=A[i]*B[i]; } + return val; } /// Calculate the dot product between a vector and itself -template <typename T> T norm( const std::vector<T>& A ){ - T val; for(unsigned i=0;i<A.size();++i){ val+=A[i]*A[i]; } - return val; +template <typename T> T norm( const std::vector<T>& A ) { + T val; for(unsigned i=0; i<A.size(); ++i) { val+=A[i]*A[i]; } + return val; } /// This class stores a full matrix and allows one to do some simple matrix operations template <typename T> class Matrix: public MatrixSquareBracketsAccess<Matrix<T>,T> - { - /// Multiply matrix by scalar - template <typename U> friend Matrix<U> operator*(U&, const Matrix<U>& ); - /// Matrix matrix multiply - template <typename U> friend void mult( const Matrix<U>& , const Matrix<U>& , Matrix<U>& ); - /// Matrix times a std::vector - template <typename U> friend void mult( const Matrix<U>&, const std::vector<U>& , std::vector<U>& ); - /// std::vector times a Matrix - template <typename U> friend void mult( const std::vector<U>&, const Matrix<U>&, std::vector<U>& ); - /// Matrix transpose - template <typename U> friend void transpose( const Matrix<U>&, Matrix<U>& ); - /// Output the entire matrix on a single line - template <typename U> friend Log& operator<<(Log&, const Matrix<U>& ); - /// Output the Matrix in matrix form - template <typename U> friend void matrixOut( Log&, const Matrix<U>& ); - /// Diagonalize a symmetric matrix - returns zero if diagonalization worked - template <typename U> friend int diagMat( const Matrix<U>& , std::vector<double>& , Matrix<double>& ); - /// Calculate the Moore-Penrose Pseudoinverse of a matrix - template <typename U> friend int pseudoInvert( const Matrix<U>& , Matrix<double>& ); - /// Calculate the logarithm of the determinant of a symmetric matrix - returns zero if succesfull - template <typename U> friend int logdet( const Matrix<U>& , double& ); - /// Invert a matrix (works for both symmetric and assymetric matrices) - returns zero if sucesfull - template <typename U> friend int Invert( const Matrix<U>& , Matrix<double>& ); - /// Do a cholesky decomposition of a matrix - template <typename U> friend void cholesky( const Matrix<U>& , Matrix<U>& ); - /// Solve a system of equations using the cholesky decomposition - template <typename U> friend void chol_elsolve( const Matrix<U>& , const std::vector<U>& , std::vector<U>& ); +{ + /// Multiply matrix by scalar + template <typename U> friend Matrix<U> operator*(U&, const Matrix<U>& ); + /// Matrix matrix multiply + template <typename U> friend void mult( const Matrix<U>&, const Matrix<U>&, Matrix<U>& ); + /// Matrix times a std::vector + template <typename U> friend void mult( const Matrix<U>&, const std::vector<U>&, std::vector<U>& ); + /// std::vector times a Matrix + template <typename U> friend void mult( const std::vector<U>&, const Matrix<U>&, std::vector<U>& ); + /// Matrix transpose + template <typename U> friend void transpose( const Matrix<U>&, Matrix<U>& ); + /// Output the entire matrix on a single line + template <typename U> friend Log& operator<<(Log&, const Matrix<U>& ); + /// Output the Matrix in matrix form + template <typename U> friend void matrixOut( Log&, const Matrix<U>& ); + /// Diagonalize a symmetric matrix - returns zero if diagonalization worked + template <typename U> friend int diagMat( const Matrix<U>&, std::vector<double>&, Matrix<double>& ); + /// Calculate the Moore-Penrose Pseudoinverse of a matrix + template <typename U> friend int pseudoInvert( const Matrix<U>&, Matrix<double>& ); + /// Calculate the logarithm of the determinant of a symmetric matrix - returns zero if succesfull + template <typename U> friend int logdet( const Matrix<U>&, double& ); + /// Invert a matrix (works for both symmetric and assymetric matrices) - returns zero if sucesfull + template <typename U> friend int Invert( const Matrix<U>&, Matrix<double>& ); + /// Do a cholesky decomposition of a matrix + template <typename U> friend void cholesky( const Matrix<U>&, Matrix<U>& ); + /// Solve a system of equations using the cholesky decomposition + template <typename U> friend void chol_elsolve( const Matrix<U>&, const std::vector<U>&, std::vector<U>& ); private: - /// Number of elements in matrix (nrows*ncols) - unsigned sz; - /// Number of rows in matrix - unsigned rw; - /// Number of columns in matrix - unsigned cl; - /// The data in the matrix - std::vector<T> data; + /// Number of elements in matrix (nrows*ncols) + unsigned sz; + /// Number of rows in matrix + unsigned rw; + /// Number of columns in matrix + unsigned cl; + /// The data in the matrix + std::vector<T> data; public: - Matrix(const unsigned nr=0, const unsigned nc=0 ) : sz(nr*nc), rw(nr), cl(nc), data(nr*nc) {} - Matrix(const Matrix<T>& t) : sz(t.sz), rw(t.rw), cl(t.cl), data(t.data) {} - /// Resize the matrix - void resize( const unsigned nr, const unsigned nc ){ rw=nr; cl=nc; sz=nr*nc; data.resize(sz); } - /// Return the number of rows - inline unsigned nrows() const { return rw; } - /// Return the number of columns - inline unsigned ncols() const { return cl; } - /// Return element i,j of the matrix - inline T operator () (const unsigned& i, const unsigned& j) const { return data[j+i*cl]; } - /// Return a referenre to element i,j of the matrix - inline T& operator () (const unsigned& i, const unsigned& j) { return data[j+i*cl]; } - /// Set all elements of the matrix equal to the value of v - Matrix<T>& operator=(const T& v){ - for(unsigned i=0;i<sz;++i){ data[i]=v; } - return *this; - } - /// Set the Matrix equal to another Matrix - Matrix<T>& operator=(const Matrix<T>& m){ - sz=m.sz; - rw=m.rw; - cl=m.cl; - data=m.data; - return *this; - } - /// Set the Matrix equal to the value of a standard vector - used for readin - Matrix<T>& operator=(const std::vector<T>& v){ - plumed_dbg_assert( v.size()==sz ); - for(unsigned i=0;i<sz;++i){ data[i]=v[i]; } - return *this; - } - /// Add v to all elements of the Matrix - Matrix<T> operator+=(const T& v){ - for(unsigned i=0;i<sz;++i){ data[i]+=v; } - return *this; - } - /// Multiply all elements by v - Matrix<T> operator*=(const T& v){ - for(unsigned i=0;i<sz;++i){ data[i]*=v; } - return *this; - } - /// Matrix addition - Matrix<T>& operator+=(const Matrix<T>& m){ + Matrix(const unsigned nr=0, const unsigned nc=0 ) : sz(nr*nc), rw(nr), cl(nc), data(nr*nc) {} + Matrix(const Matrix<T>& t) : sz(t.sz), rw(t.rw), cl(t.cl), data(t.data) {} + /// Resize the matrix + void resize( const unsigned nr, const unsigned nc ) { rw=nr; cl=nc; sz=nr*nc; data.resize(sz); } + /// Return the number of rows + inline unsigned nrows() const { return rw; } + /// Return the number of columns + inline unsigned ncols() const { return cl; } + /// Return element i,j of the matrix + inline T operator () (const unsigned& i, const unsigned& j) const { return data[j+i*cl]; } + /// Return a referenre to element i,j of the matrix + inline T& operator () (const unsigned& i, const unsigned& j) { return data[j+i*cl]; } + /// Set all elements of the matrix equal to the value of v + Matrix<T>& operator=(const T& v) { + for(unsigned i=0; i<sz; ++i) { data[i]=v; } + return *this; + } + /// Set the Matrix equal to another Matrix + Matrix<T>& operator=(const Matrix<T>& m) { + sz=m.sz; + rw=m.rw; + cl=m.cl; + data=m.data; + return *this; + } + /// Set the Matrix equal to the value of a standard vector - used for readin + Matrix<T>& operator=(const std::vector<T>& v) { + plumed_dbg_assert( v.size()==sz ); + for(unsigned i=0; i<sz; ++i) { data[i]=v[i]; } + return *this; + } + /// Add v to all elements of the Matrix + Matrix<T> operator+=(const T& v) { + for(unsigned i=0; i<sz; ++i) { data[i]+=v; } + return *this; + } + /// Multiply all elements by v + Matrix<T> operator*=(const T& v) { + for(unsigned i=0; i<sz; ++i) { data[i]*=v; } + return *this; + } + /// Matrix addition + Matrix<T>& operator+=(const Matrix<T>& m) { plumed_dbg_assert( m.rw==rw && m.cl==cl ); data+=m.data; return *this; } /// Subtract v from all elements of the Matrix - Matrix<T> operator-=(const T& v){ - for(unsigned i=0;i<sz;++i){ data-=v; } - return *this; + Matrix<T> operator-=(const T& v) { + for(unsigned i=0; i<sz; ++i) { data-=v; } + return *this; } /// Matrix subtraction - Matrix<T>& operator-=(const Matrix<T>& m){ + Matrix<T>& operator-=(const Matrix<T>& m) { plumed_dbg_assert( m.rw==rw && m.cl==cl ); - data-=m.data; + data-=m.data; return *this; } /// Test if the matrix is symmetric or not - unsigned isSymmetric() const { - if (rw!=cl){ return 0; } - unsigned sym=1; - for(unsigned i=1;i<rw;++i) for(unsigned j=0;j<i;++j) if( std::fabs(data[i+j*cl]-data[j+i*cl])>1.e-10 ){ sym=0; break; } - return sym; + unsigned isSymmetric() const { + if (rw!=cl) { return 0; } + unsigned sym=1; + for(unsigned i=1; i<rw; ++i) for(unsigned j=0; j<i; ++j) if( std::fabs(data[i+j*cl]-data[j+i*cl])>1.e-10 ) { sym=0; break; } + return sym; } }; /// Multiply matrix by scalar -template <typename T> Matrix<T> operator*(T& v, const Matrix<T>& m ){ +template <typename T> Matrix<T> operator*(T& v, const Matrix<T>& m ) { Matrix<T> new_m(m); new_m*=v; - return new_m; + return new_m; } -template <typename T> void mult( const Matrix<T>& A , const Matrix<T>& B , Matrix<T>& C ){ +template <typename T> void mult( const Matrix<T>& A, const Matrix<T>& B, Matrix<T>& C ) { plumed_assert(A.cl==B.rw); - if( A.rw !=C.rw || B.cl !=C.cl ){ C.resize( A.rw , B.cl ); } C=static_cast<T>( 0 ); - for(unsigned i=0;i<A.rw;++i) for(unsigned j=0;j<B.cl;++j) for (unsigned k=0; k<A.cl; ++k) C(i,j)+=A(i,k)*B(k,j); + if( A.rw !=C.rw || B.cl !=C.cl ) { C.resize( A.rw, B.cl ); } C=static_cast<T>( 0 ); + for(unsigned i=0; i<A.rw; ++i) for(unsigned j=0; j<B.cl; ++j) for (unsigned k=0; k<A.cl; ++k) C(i,j)+=A(i,k)*B(k,j); } -template <typename T> void mult( const Matrix<T>& A, const std::vector<T>& B, std::vector<T>& C){ +template <typename T> void mult( const Matrix<T>& A, const std::vector<T>& B, std::vector<T>& C) { plumed_assert( A.cl==B.size() ); - if( C.size()!=A.rw ){ C.resize(A.rw); } - for(unsigned i=0;i<A.rw;++i){ C[i]= static_cast<T>( 0 ); } - for(unsigned i=0;i<A.rw;++i) for(unsigned k=0;k<A.cl;++k) C[i]+=A(i,k)*B[k] ; + if( C.size()!=A.rw ) { C.resize(A.rw); } + for(unsigned i=0; i<A.rw; ++i) { C[i]= static_cast<T>( 0 ); } + for(unsigned i=0; i<A.rw; ++i) for(unsigned k=0; k<A.cl; ++k) C[i]+=A(i,k)*B[k] ; } -template <typename T> void mult( const std::vector<T>& A, const Matrix<T>& B, std::vector<T>& C){ +template <typename T> void mult( const std::vector<T>& A, const Matrix<T>& B, std::vector<T>& C) { plumed_assert( B.rw==A.size() ); - if( C.size()!=B.cl ){C.resize( B.cl );} - for(unsigned i=0;i<B.cl;++i){ C[i]=static_cast<T>( 0 ); } - for(unsigned i=0;i<B.cl;++i) for(unsigned k=0;k<B.rw;++k) C[i]+=A[k]*B(k,i); + if( C.size()!=B.cl ) {C.resize( B.cl );} + for(unsigned i=0; i<B.cl; ++i) { C[i]=static_cast<T>( 0 ); } + for(unsigned i=0; i<B.cl; ++i) for(unsigned k=0; k<B.rw; ++k) C[i]+=A[k]*B(k,i); } -template <typename T> void transpose( const Matrix<T>& A, Matrix<T>& AT ){ - if( A.rw!=AT.cl || A.cl!=AT.rw ) AT.resize( A.cl , A.rw ); - for(unsigned i=0;i<A.cl;++i) for(unsigned j=0;j<A.rw;++j) AT(i,j)=A(j,i); +template <typename T> void transpose( const Matrix<T>& A, Matrix<T>& AT ) { + if( A.rw!=AT.cl || A.cl!=AT.rw ) AT.resize( A.cl, A.rw ); + for(unsigned i=0; i<A.cl; ++i) for(unsigned j=0; j<A.rw; ++j) AT(i,j)=A(j,i); } -template <typename T> Log& operator<<(Log& ostr, const Matrix<T>& mat){ - for(unsigned i=0;i<mat.sz;++i) ostr<<mat.data[i]<<" "; - return ostr; +template <typename T> Log& operator<<(Log& ostr, const Matrix<T>& mat) { + for(unsigned i=0; i<mat.sz; ++i) ostr<<mat.data[i]<<" "; + return ostr; } -template <typename T> void matrixOut( Log& ostr, const Matrix<T>& mat){ - for(unsigned i=0;i<mat.rw;++i){ - for(unsigned j=0;j<mat.cl;++j){ ostr<<mat(i,j)<<" "; } - ostr<<"\n"; - } - return; +template <typename T> void matrixOut( Log& ostr, const Matrix<T>& mat) { + for(unsigned i=0; i<mat.rw; ++i) { + for(unsigned j=0; j<mat.cl; ++j) { ostr<<mat(i,j)<<" "; } + ostr<<"\n"; + } + return; } -template <typename T> int diagMat( const Matrix<T>& A, std::vector<double>& eigenvals, Matrix<double>& eigenvecs ){ - - // Check matrix is square and symmetric - plumed_assert( A.rw==A.cl ); plumed_assert( A.isSymmetric()==1 ); - double *da=new double[A.sz]; unsigned k=0; double *evals=new double[ A.cl ]; - // Transfer the matrix to the local array - for (unsigned i=0; i<A.cl; ++i) for (unsigned j=0; j<A.rw; ++j) da[k++]=static_cast<double>( A(j,i) ); - - int n=A.cl; int lwork=-1, liwork=-1, m, info, one=1; - double *work=new double[A.cl]; int *iwork=new int[A.cl]; - double vl, vu, abstol=0.0; - int* isup=new int[2*A.cl]; double *evecs=new double[A.sz]; - - plumed_lapack_dsyevr("V", "I", "U", &n, da, &n, &vl, &vu, &one, &n , - &abstol, &m, evals, evecs, &n, - isup, work, &lwork, iwork, &liwork, &info); - if (info!=0) return info; - - // Retrieve correct sizes for work and iwork then reallocate - liwork=iwork[0]; delete [] iwork; iwork=new int[liwork]; - lwork=static_cast<int>( work[0] ); delete [] work; work=new double[lwork]; - - plumed_lapack_dsyevr("V", "I", "U", &n, da, &n, &vl, &vu, &one, &n , - &abstol, &m, evals, evecs, &n, - isup, work, &lwork, iwork, &liwork, &info); - if (info!=0) return info; - - if( eigenvals.size()!=A.cl ){ eigenvals.resize( A.cl ); } - if( eigenvecs.rw!=A.rw || eigenvecs.cl!=A.cl ){ eigenvecs.resize( A.rw, A.cl ); } - k=0; - for(unsigned i=0;i<A.cl;++i){ - eigenvals[i]=evals[i]; - // N.B. For ease of producing projectors we store the eigenvectors - // ROW-WISE in the eigenvectors matrix. The first index is the - // eigenvector number and the second the component - for(unsigned j=0;j<A.rw;++j){ eigenvecs(i,j)=evecs[k++]; } - } - - // This changes eigenvectors so that the first non-null element - // of each of them is positive - // We can do it because the phase is arbitrary, and helps making - // the result reproducible - for(int i=0;i<n;++i) { - int j; - for(j=0;j<n;j++) if(eigenvecs(i,j)*eigenvecs(i,j)>1e-14) break; - if(j<n) if(eigenvecs(i,j)<0.0) for(j=0;j<n;j++) eigenvecs(i,j)*=-1; - } - - // Deallocate all the memory used by the various arrays - delete[] da; delete [] work; delete [] evals; delete[] evecs; delete [] iwork; delete [] isup; - return 0; +template <typename T> int diagMat( const Matrix<T>& A, std::vector<double>& eigenvals, Matrix<double>& eigenvecs ) { + + // Check matrix is square and symmetric + plumed_assert( A.rw==A.cl ); plumed_assert( A.isSymmetric()==1 ); + double *da=new double[A.sz]; unsigned k=0; double *evals=new double[ A.cl ]; + // Transfer the matrix to the local array + for (unsigned i=0; i<A.cl; ++i) for (unsigned j=0; j<A.rw; ++j) da[k++]=static_cast<double>( A(j,i) ); + + int n=A.cl; int lwork=-1, liwork=-1, m, info, one=1; + double *work=new double[A.cl]; int *iwork=new int[A.cl]; + double vl, vu, abstol=0.0; + int* isup=new int[2*A.cl]; double *evecs=new double[A.sz]; + + plumed_lapack_dsyevr("V", "I", "U", &n, da, &n, &vl, &vu, &one, &n, + &abstol, &m, evals, evecs, &n, + isup, work, &lwork, iwork, &liwork, &info); + if (info!=0) return info; + + // Retrieve correct sizes for work and iwork then reallocate + liwork=iwork[0]; delete [] iwork; iwork=new int[liwork]; + lwork=static_cast<int>( work[0] ); delete [] work; work=new double[lwork]; + + plumed_lapack_dsyevr("V", "I", "U", &n, da, &n, &vl, &vu, &one, &n, + &abstol, &m, evals, evecs, &n, + isup, work, &lwork, iwork, &liwork, &info); + if (info!=0) return info; + + if( eigenvals.size()!=A.cl ) { eigenvals.resize( A.cl ); } + if( eigenvecs.rw!=A.rw || eigenvecs.cl!=A.cl ) { eigenvecs.resize( A.rw, A.cl ); } + k=0; + for(unsigned i=0; i<A.cl; ++i) { + eigenvals[i]=evals[i]; + // N.B. For ease of producing projectors we store the eigenvectors + // ROW-WISE in the eigenvectors matrix. The first index is the + // eigenvector number and the second the component + for(unsigned j=0; j<A.rw; ++j) { eigenvecs(i,j)=evecs[k++]; } + } + + // This changes eigenvectors so that the first non-null element + // of each of them is positive + // We can do it because the phase is arbitrary, and helps making + // the result reproducible + for(int i=0; i<n; ++i) { + int j; + for(j=0; j<n; j++) if(eigenvecs(i,j)*eigenvecs(i,j)>1e-14) break; + if(j<n) if(eigenvecs(i,j)<0.0) for(j=0; j<n; j++) eigenvecs(i,j)*=-1; + } + + // Deallocate all the memory used by the various arrays + delete[] da; delete [] work; delete [] evals; delete[] evecs; delete [] iwork; delete [] isup; + return 0; } -template <typename T> int pseudoInvert( const Matrix<T>& A, Matrix<double>& pseudoinverse ){ - double *da=new double[A.sz]; unsigned k=0; +template <typename T> int pseudoInvert( const Matrix<T>& A, Matrix<double>& pseudoinverse ) { + double *da=new double[A.sz]; unsigned k=0; // Transfer the matrix to the local array for (unsigned i=0; i<A.cl; ++i) for (unsigned j=0; j<A.rw; ++j) da[k++]=static_cast<double>( A(j,i) ); - int nsv, info, nrows=A.rw, ncols=A.cl; - if(A.rw>A.cl){nsv=A.cl;}else{nsv=A.rw;} + int nsv, info, nrows=A.rw, ncols=A.cl; + if(A.rw>A.cl) {nsv=A.cl;} else {nsv=A.rw;} // Create some containers for stuff from single value decomposition double *S=new double[nsv]; double *U=new double[nrows*nrows]; @@ -274,19 +274,19 @@ template <typename T> int pseudoInvert( const Matrix<T>& A, Matrix<double>& pseu // This does the singular value decomposition plumed_lapack_dgesdd( "A", &nrows, &ncols, da, &nrows, S, U, &nrows, VT, &ncols, work, &lwork, iwork, &info ); - if(info!=0) return info; + if(info!=0) return info; // Compute the tolerance on the singular values ( machine epsilon * number of singular values * maximum singular value ) - double tol; tol=S[0]; for(int i=1;i<nsv;++i){ if( S[i]>tol ){ tol=S[i]; } } tol*=nsv*epsilon; + double tol; tol=S[0]; for(int i=1; i<nsv; ++i) { if( S[i]>tol ) { tol=S[i]; } } tol*=nsv*epsilon; // Get the inverses of the singlular values Matrix<double> Si( ncols, nrows ); Si=0.0; - for(int i=0;i<nsv;++i){ if( S[i]>tol ){ Si(i,i)=1./S[i]; }else{ Si(i,i)=0.0; } } + for(int i=0; i<nsv; ++i) { if( S[i]>tol ) { Si(i,i)=1./S[i]; } else { Si(i,i)=0.0; } } // Now extract matrices for pseudoinverse - Matrix<double> V( ncols, ncols ), UT( nrows, nrows ), tmp( ncols, nrows ); - k=0; for(int i=0;i<nrows;++i){ for(int j=0;j<nrows;++j){ UT(i,j)=U[k++]; } } - k=0; for(int i=0;i<ncols;++i){ for(int j=0;j<ncols;++j){ V(i,j)=VT[k++]; } } + Matrix<double> V( ncols, ncols ), UT( nrows, nrows ), tmp( ncols, nrows ); + k=0; for(int i=0; i<nrows; ++i) { for(int j=0; j<nrows; ++j) { UT(i,j)=U[k++]; } } + k=0; for(int i=0; i<ncols; ++i) { for(int j=0; j<ncols; ++j) { V(i,j)=VT[k++]; } } // And do matrix algebra to construct the pseudoinverse if( pseudoinverse.rw!=ncols || pseudoinverse.cl!=nrows ) pseudoinverse.resize( ncols, nrows ); @@ -297,111 +297,111 @@ template <typename T> int pseudoInvert( const Matrix<T>& A, Matrix<double>& pseu return 0; } -template <typename T> int Invert( const Matrix<T>& A, Matrix<double>& inverse ){ - - if( A.isSymmetric()==1 ){ - // GAT -- I only ever use symmetric matrices so I can invert them like this. - // I choose to do this as I have had problems with the more general way of doing this that - // is implemented below. - std::vector<double> eval(A.rw); Matrix<double> evec(A.rw,A.cl), tevec(A.rw,A.cl); - int err; err=diagMat( A, eval, evec ); - if(err!=0) return err; - for (unsigned i=0; i<A.rw; ++i) for (unsigned j=0; j<A.cl; ++j) tevec(i,j)=evec(j,i)/eval[j]; - mult(tevec,evec,inverse); +template <typename T> int Invert( const Matrix<T>& A, Matrix<double>& inverse ) { + + if( A.isSymmetric()==1 ) { + // GAT -- I only ever use symmetric matrices so I can invert them like this. + // I choose to do this as I have had problems with the more general way of doing this that + // is implemented below. + std::vector<double> eval(A.rw); Matrix<double> evec(A.rw,A.cl), tevec(A.rw,A.cl); + int err; err=diagMat( A, eval, evec ); + if(err!=0) return err; + for (unsigned i=0; i<A.rw; ++i) for (unsigned j=0; j<A.cl; ++j) tevec(i,j)=evec(j,i)/eval[j]; + mult(tevec,evec,inverse); } else { - double *da=new double[A.sz]; int *ipiv=new int[A.cl]; - unsigned k=0; int n=A.rw, info; - for(unsigned i=0;i<A.cl;++i) for(unsigned j=0;j<A.rw;++j) da[k++]=static_cast<double>( A(j,i) ); + double *da=new double[A.sz]; int *ipiv=new int[A.cl]; + unsigned k=0; int n=A.rw, info; + for(unsigned i=0; i<A.cl; ++i) for(unsigned j=0; j<A.rw; ++j) da[k++]=static_cast<double>( A(j,i) ); - plumed_lapack_dgetrf(&n,&n,da,&n,ipiv,&info); - if(info!=0) return info; + plumed_lapack_dgetrf(&n,&n,da,&n,ipiv,&info); + if(info!=0) return info; - int lwork=-1; double* work=new double[A.cl]; - plumed_lapack_dgetri(&n,da,&n,ipiv,work,&lwork,&info); - if(info!=0) return info; + int lwork=-1; double* work=new double[A.cl]; + plumed_lapack_dgetri(&n,da,&n,ipiv,work,&lwork,&info); + if(info!=0) return info; - lwork=static_cast<int>( work[0] ); delete [] work; work=new double[lwork]; - plumed_lapack_dgetri(&n,da,&n,ipiv,work,&lwork,&info); - if(info!=0) return info; + lwork=static_cast<int>( work[0] ); delete [] work; work=new double[lwork]; + plumed_lapack_dgetri(&n,da,&n,ipiv,work,&lwork,&info); + if(info!=0) return info; - if( inverse.cl!=A.cl || inverse.rw!=A.rw ){ inverse.resize(A.rw,A.cl); } - k=0; for(unsigned i=0;i<A.rw;++i) for(unsigned j=0;j<A.cl;++j) inverse(j,i)=da[k++]; + if( inverse.cl!=A.cl || inverse.rw!=A.rw ) { inverse.resize(A.rw,A.cl); } + k=0; for(unsigned i=0; i<A.rw; ++i) for(unsigned j=0; j<A.cl; ++j) inverse(j,i)=da[k++]; - delete[] work; delete[] ipiv; + delete[] work; delete[] ipiv; } return 0; } -template <typename T> void cholesky( const Matrix<T>& A, Matrix<T>& B ){ +template <typename T> void cholesky( const Matrix<T>& A, Matrix<T>& B ) { - plumed_assert( A.rw==A.cl && A.isSymmetric() ); - Matrix<T> L(A.rw ,A.cl); L=0.; - std::vector<T> D(A.rw,0.); - for(unsigned i=0; i<A.rw; ++i){ + plumed_assert( A.rw==A.cl && A.isSymmetric() ); + Matrix<T> L(A.rw,A.cl); L=0.; + std::vector<T> D(A.rw,0.); + for(unsigned i=0; i<A.rw; ++i) { // The following line triggers a warning in cppcheck, // perhaps because of the conversion of "1" to an unspecified type // I suppress it explicitly // cppcheck-suppress compareBoolExpressionWithInt - L(i,i)=static_cast<T>( 1 ); - for (unsigned j=0; j<i; ++j){ - L(i,j)=A(i,j); - for (unsigned k=0; k<j; ++k) L(i,j)-=L(i,k)*L(j,k)*D[k]; - if (D[j]!=0.) L(i,j)/=D[j]; else L(i,j)=static_cast<T>( 0 ); - } - D[i]=A(i,i); - for (unsigned k=0; k<i; ++k) D[i]-=L(i,k)*L(i,k)*D[k]; - } - - for(unsigned i=0; i<A.rw; ++i) D[i]=(D[i]>0.?sqrt(D[i]):0.); - if( B.rw!=A.rw || B.cl!=A.cl ){ B.resize( A.rw, A.cl); } - B=0.; for(unsigned i=0; i<A.rw; ++i) for(unsigned j=0; j<=i; ++j) B(i,j)+=L(i,j)*D[j]; + L(i,i)=static_cast<T>( 1 ); + for (unsigned j=0; j<i; ++j) { + L(i,j)=A(i,j); + for (unsigned k=0; k<j; ++k) L(i,j)-=L(i,k)*L(j,k)*D[k]; + if (D[j]!=0.) L(i,j)/=D[j]; else L(i,j)=static_cast<T>( 0 ); + } + D[i]=A(i,i); + for (unsigned k=0; k<i; ++k) D[i]-=L(i,k)*L(i,k)*D[k]; + } + + for(unsigned i=0; i<A.rw; ++i) D[i]=(D[i]>0.?sqrt(D[i]):0.); + if( B.rw!=A.rw || B.cl!=A.cl ) { B.resize( A.rw, A.cl); } + B=0.; for(unsigned i=0; i<A.rw; ++i) for(unsigned j=0; j<=i; ++j) B(i,j)+=L(i,j)*D[j]; } -template <typename T> void chol_elsolve( const Matrix<T>& M, const std::vector<T>& b, std::vector<T>& y ){ +template <typename T> void chol_elsolve( const Matrix<T>& M, const std::vector<T>& b, std::vector<T>& y ) { - plumed_assert( M.rw==M.cl && M(0,1)==0.0 && b.size()==M.rw ); - if( y.size()!=M.rw ){ y.resize( M.rw ); } - for(unsigned i=0;i<M.rw;++i){ - y[i]=b[i]; - for(unsigned j=0;j<i;++j) y[i]-=M(i,j)*y[j]; - y[i]*=1.0/M(i,i); - } + plumed_assert( M.rw==M.cl && M(0,1)==0.0 && b.size()==M.rw ); + if( y.size()!=M.rw ) { y.resize( M.rw ); } + for(unsigned i=0; i<M.rw; ++i) { + y[i]=b[i]; + for(unsigned j=0; j<i; ++j) y[i]-=M(i,j)*y[j]; + y[i]*=1.0/M(i,i); + } } -template <typename T> int logdet( const Matrix<T>& M, double& ldet ){ - // Check matrix is square and symmetric - plumed_assert( M.rw==M.cl || M.isSymmetric() ); +template <typename T> int logdet( const Matrix<T>& M, double& ldet ) { + // Check matrix is square and symmetric + plumed_assert( M.rw==M.cl || M.isSymmetric() ); - double *da=new double[M.sz]; unsigned k=0; double *evals=new double[M.cl]; - // Transfer the matrix to the local array - for (unsigned i=0; i<M.rw; ++i) for (unsigned j=0; j<M.cl; ++j) da[k++]=static_cast<double>( M(j,i) ); + double *da=new double[M.sz]; unsigned k=0; double *evals=new double[M.cl]; + // Transfer the matrix to the local array + for (unsigned i=0; i<M.rw; ++i) for (unsigned j=0; j<M.cl; ++j) da[k++]=static_cast<double>( M(j,i) ); - int n=M.cl; int lwork=-1, liwork=-1, info, m, one=1; - double *work=new double[M.rw]; int *iwork=new int[M.rw]; - double vl, vu, abstol=0.0; - int* isup=new int[2*M.rw]; double *evecs=new double[M.sz]; - plumed_lapack_dsyevr("N", "I", "U", &n, da, &n, &vl, &vu, &one, &n , - &abstol, &m, evals, evecs, &n, - isup, work, &lwork, iwork, &liwork, &info); - if (info!=0) return info; + int n=M.cl; int lwork=-1, liwork=-1, info, m, one=1; + double *work=new double[M.rw]; int *iwork=new int[M.rw]; + double vl, vu, abstol=0.0; + int* isup=new int[2*M.rw]; double *evecs=new double[M.sz]; + plumed_lapack_dsyevr("N", "I", "U", &n, da, &n, &vl, &vu, &one, &n, + &abstol, &m, evals, evecs, &n, + isup, work, &lwork, iwork, &liwork, &info); + if (info!=0) return info; - // Retrieve correct sizes for work and iwork then reallocate - lwork=static_cast<int>( work[0] ); delete [] work; work=new double[lwork]; - liwork=iwork[0]; delete [] iwork; iwork=new int[liwork]; + // Retrieve correct sizes for work and iwork then reallocate + lwork=static_cast<int>( work[0] ); delete [] work; work=new double[lwork]; + liwork=iwork[0]; delete [] iwork; iwork=new int[liwork]; - plumed_lapack_dsyevr("N", "I", "U", &n, da, &n, &vl, &vu, &one, &n , - &abstol, &m, evals, evecs, &n, - isup, work, &lwork, iwork, &liwork, &info); - if (info!=0) return info; + plumed_lapack_dsyevr("N", "I", "U", &n, da, &n, &vl, &vu, &one, &n, + &abstol, &m, evals, evecs, &n, + isup, work, &lwork, iwork, &liwork, &info); + if (info!=0) return info; - // Transfer the eigenvalues and eigenvectors to the output - ldet=0; for(unsigned i=0;i<M.cl;i++){ ldet+=log(evals[i]); } + // Transfer the eigenvalues and eigenvectors to the output + ldet=0; for(unsigned i=0; i<M.cl; i++) { ldet+=log(evals[i]); } - // Deallocate all the memory used by the various arrays - delete[] da; delete [] work; delete [] evals; delete[] evecs; delete [] iwork; delete [] isup; + // Deallocate all the memory used by the various arrays + delete[] da; delete [] work; delete [] evals; delete[] evecs; delete [] iwork; delete [] isup; - return 0; + return 0; } diff --git a/src/tools/MatrixSquareBracketsAccess.h b/src/tools/MatrixSquareBracketsAccess.h index c63731463..1e8188bb3 100644 --- a/src/tools/MatrixSquareBracketsAccess.h +++ b/src/tools/MatrixSquareBracketsAccess.h @@ -22,7 +22,7 @@ #ifndef __PLUMED_tools_MatrixSquareBracketsAccess_h #define __PLUMED_tools_MatrixSquareBracketsAccess_h -namespace PLMD{ +namespace PLMD { /** Utility class to add [][] access @@ -66,27 +66,27 @@ int main(){ */ template<class T,class C,class I=unsigned,class J=unsigned> -class MatrixSquareBracketsAccess{ +class MatrixSquareBracketsAccess { /// Small utility class which just contains a pointer to the T and the row number - class Const_row{ + class Const_row { friend class MatrixSquareBracketsAccess; // this so as to allow only T to instantiate Const_row - // the user should not manipulate it directly + // the user should not manipulate it directly const MatrixSquareBracketsAccess& t; const I i; Const_row(const MatrixSquareBracketsAccess&t,I i); // constructor is private and cannot be manipulated by the user public: - /// access element + /// access element const C & operator[] (J j)const; }; /// Small utility class which just contains a pointer to the T and the row number - class Row{ + class Row { friend class MatrixSquareBracketsAccess; // this so as to allow only T to instantiate Const_row - // the user should not manipulate it directly + // the user should not manipulate it directly MatrixSquareBracketsAccess& t; const I i; Row(MatrixSquareBracketsAccess&t,I i); // constructor is private and cannot be manipulated by the user public: - /// access element + /// access element C & operator[] (J j); }; public: @@ -98,29 +98,29 @@ public: template<class T,class C,class I,class J> MatrixSquareBracketsAccess<T,C,I,J>::Const_row::Const_row(const MatrixSquareBracketsAccess&t,I i): - t(t),i(i){} + t(t),i(i) {} template<class T,class C,class I,class J> MatrixSquareBracketsAccess<T,C,I,J>::Row::Row(MatrixSquareBracketsAccess&t,I i): - t(t),i(i){} + t(t),i(i) {} template<class T,class C,class I,class J> -const C & MatrixSquareBracketsAccess<T,C,I,J>::Const_row::operator[] (J j)const{ +const C & MatrixSquareBracketsAccess<T,C,I,J>::Const_row::operator[] (J j)const { return (*static_cast<const T*>(&t))(i,j); } template<class T,class C,class I,class J> -C & MatrixSquareBracketsAccess<T,C,I,J>::Row::operator[] (J j){ +C & MatrixSquareBracketsAccess<T,C,I,J>::Row::operator[] (J j) { return (*static_cast<T*>(&t))(i,j); } template<class T,class C,class I,class J> -typename MatrixSquareBracketsAccess<T,C,I,J>::Row MatrixSquareBracketsAccess<T,C,I,J>::operator[] (I i){ +typename MatrixSquareBracketsAccess<T,C,I,J>::Row MatrixSquareBracketsAccess<T,C,I,J>::operator[] (I i) { return Row(*this,i); } template<class T,class C,class I,class J> -typename MatrixSquareBracketsAccess<T,C,I,J>::Const_row MatrixSquareBracketsAccess<T,C,I,J>::operator[] (I i)const{ +typename MatrixSquareBracketsAccess<T,C,I,J>::Const_row MatrixSquareBracketsAccess<T,C,I,J>::operator[] (I i)const { return Const_row(*this,i); } diff --git a/src/tools/Minimise1DBrent.h b/src/tools/Minimise1DBrent.h index dca7800e9..097a05b44 100644 --- a/src/tools/Minimise1DBrent.h +++ b/src/tools/Minimise1DBrent.h @@ -27,7 +27,7 @@ #include <vector> #include <string> -namespace PLMD{ +namespace PLMD { /// A class for doing parabolic interpolation and minimisation of /// 1D functions using Brent's method. @@ -50,7 +50,7 @@ private: const unsigned ITMAX; /// The value of the golden ratio const double CGOLD; -/// A small number that protects against trying to achieve fractional +/// A small number that protects against trying to achieve fractional /// accuracy for a minimum that happens to be exactly zero const double ZEPS; /// This is the type specifier for the function to minimise @@ -61,128 +61,128 @@ private: FCLASS myclass_func; public: explicit Minimise1DBrent( const FCLASS& pf, const double& t=3.0E-8 ); -/// Bracket the minium +/// Bracket the minium void bracket( const double& ax, const double& xx, eng_pointer eng ); /// Find the minimum between two brackets - double minimise( eng_pointer eng ); + double minimise( eng_pointer eng ); /// Return the value of the function at the minimum double getMinimumValue() const ; }; template <class FCLASS> Minimise1DBrent<FCLASS>::Minimise1DBrent( const FCLASS& pf, const double& t ): -bracketed(false), -minimised(false), -tol(t), -GOLD(1.618034), -GLIMIT(100.0), -TINY(1.0E-20), -ITMAX(100), -CGOLD(0.3819660), -ZEPS(epsilon*1.0E-3), -ax(0),bx(0),cx(0), -fa(0),fb(0),fc(0), -fmin(0), -myclass_func(pf) + bracketed(false), + minimised(false), + tol(t), + GOLD(1.618034), + GLIMIT(100.0), + TINY(1.0E-20), + ITMAX(100), + CGOLD(0.3819660), + ZEPS(epsilon*1.0E-3), + ax(0),bx(0),cx(0), + fa(0),fb(0),fc(0), + fmin(0), + myclass_func(pf) { } template <class FCLASS> -void Minimise1DBrent<FCLASS>::bracket( const double& a, const double& b, eng_pointer eng ){ - ax=a; bx=b; double fu; - fa=(myclass_func.*eng)(ax); fb=(myclass_func.*eng)(bx); - if( fb>fa ){ - double tmp; - tmp=ax; ax=bx; bx=tmp; - tmp=fa; fa=fb; fb=tmp; - } - cx=bx+GOLD*(bx-ax); - fc=(myclass_func.*eng)(cx); - while ( fb > fc ){ - double r=(bx-ax)*(fb-fc); - double q=(bx-cx)*(fb-fa); - double u=bx-((bx-cx)*q-(bx-ax)*r)/(2.0*(fabs(q-r)>TINY?fabs(q-r):TINY)*(q-r>=0?1:-1)); - double ulim=bx+GLIMIT*(cx-bx); - if((bx-u)*(u-cx) > 0.0 ){ - fu=(myclass_func.*eng)(u); - if( fu < fc ){ - ax=bx; bx=u; fa=fb; fb=fu; bracketed=true; return; - } else if( fu > fb ){ - cx=u; fc=fu; bracketed=true; return; - } - u=cx+GOLD*(cx-bx); fu=(myclass_func.*eng)(u); - } else if((cx-u)*(u-ulim) > 0.0 ){ - fu=(myclass_func.*eng)(u); - if( fu<fc ){ - bx=cx; cx=u; u+=GOLD*(u-bx); - fb=fc; fc=fu; fu=(myclass_func.*eng)(u); - } - } else if( (u-ulim)*(ulim-cx) >= 0.0 ){ - u=ulim; - fu=(myclass_func.*eng)(u); - } else { - u=cx+GOLD*(cx-bx); - fu=(myclass_func.*eng)(u); - } - ax=bx; bx=cx; cx=u; - fa=fb; fb=fc; fc=fu; - } - bracketed=true; +void Minimise1DBrent<FCLASS>::bracket( const double& a, const double& b, eng_pointer eng ) { + ax=a; bx=b; double fu; + fa=(myclass_func.*eng)(ax); fb=(myclass_func.*eng)(bx); + if( fb>fa ) { + double tmp; + tmp=ax; ax=bx; bx=tmp; + tmp=fa; fa=fb; fb=tmp; + } + cx=bx+GOLD*(bx-ax); + fc=(myclass_func.*eng)(cx); + while ( fb > fc ) { + double r=(bx-ax)*(fb-fc); + double q=(bx-cx)*(fb-fa); + double u=bx-((bx-cx)*q-(bx-ax)*r)/(2.0*(fabs(q-r)>TINY?fabs(q-r):TINY)*(q-r>=0?1:-1)); + double ulim=bx+GLIMIT*(cx-bx); + if((bx-u)*(u-cx) > 0.0 ) { + fu=(myclass_func.*eng)(u); + if( fu < fc ) { + ax=bx; bx=u; fa=fb; fb=fu; bracketed=true; return; + } else if( fu > fb ) { + cx=u; fc=fu; bracketed=true; return; + } + u=cx+GOLD*(cx-bx); fu=(myclass_func.*eng)(u); + } else if((cx-u)*(u-ulim) > 0.0 ) { + fu=(myclass_func.*eng)(u); + if( fu<fc ) { + bx=cx; cx=u; u+=GOLD*(u-bx); + fb=fc; fc=fu; fu=(myclass_func.*eng)(u); + } + } else if( (u-ulim)*(ulim-cx) >= 0.0 ) { + u=ulim; + fu=(myclass_func.*eng)(u); + } else { + u=cx+GOLD*(cx-bx); + fu=(myclass_func.*eng)(u); + } + ax=bx; bx=cx; cx=u; + fa=fb; fb=fc; fc=fu; + } + bracketed=true; } template <class FCLASS> -double Minimise1DBrent<FCLASS>::minimise( eng_pointer eng ){ - plumed_dbg_assert( bracketed ); - - double a,b,d=0.0,etemp,fu,fv,fw,fx; - double p,q,r,tol1,tol2,u,v,w,x,xm; - double e=0.0; - - a=(ax < cx ? ax : cx ); - b=(ax >= cx ? ax : cx ); - x=w=v=bx; - fw=fv=fx=(myclass_func.*eng)(x); - for(unsigned iter=0;iter<ITMAX;++iter){ - xm=0.5*(a+b); - tol2=2.0*(tol1=tol*fabs(x)+ZEPS); - if( fabs(x-xm) <= (tol2-0.5*(b-a))) { - fmin=fx; minimised=true; return x; - } - if( fabs(e) > tol1 ){ - r=(x-w)*(fx-fv); - q=(x-v)*(fx-fw); - p=(x-v)*q-(x-w)*r; - q=2.0*(q-r); - if( q > 0.0 ) p = -p; - q=fabs(q); - etemp=e; - e=d; - if( fabs(p) >= fabs(0.5*q*etemp) || p <= q*(a-x) || p >= q*(b-x) ){ - d = CGOLD*(e=(x >= xm ? a-x : b-x )); - } else { - d=p/q; u=x+d; - if(u-a < tol2 || b-u < tol2 ) d=(xm-x>=0?fabs(tol1):-fabs(tol1)); - } +double Minimise1DBrent<FCLASS>::minimise( eng_pointer eng ) { + plumed_dbg_assert( bracketed ); + + double a,b,d=0.0,etemp,fu,fv,fw,fx; + double p,q,r,tol1,tol2,u,v,w,x,xm; + double e=0.0; + + a=(ax < cx ? ax : cx ); + b=(ax >= cx ? ax : cx ); + x=w=v=bx; + fw=fv=fx=(myclass_func.*eng)(x); + for(unsigned iter=0; iter<ITMAX; ++iter) { + xm=0.5*(a+b); + tol2=2.0*(tol1=tol*fabs(x)+ZEPS); + if( fabs(x-xm) <= (tol2-0.5*(b-a))) { + fmin=fx; minimised=true; return x; + } + if( fabs(e) > tol1 ) { + r=(x-w)*(fx-fv); + q=(x-v)*(fx-fw); + p=(x-v)*q-(x-w)*r; + q=2.0*(q-r); + if( q > 0.0 ) p = -p; + q=fabs(q); + etemp=e; + e=d; + if( fabs(p) >= fabs(0.5*q*etemp) || p <= q*(a-x) || p >= q*(b-x) ) { + d = CGOLD*(e=(x >= xm ? a-x : b-x )); } else { - d=CGOLD*(e=( x >= xm ? a-x : b-x )); + d=p/q; u=x+d; + if(u-a < tol2 || b-u < tol2 ) d=(xm-x>=0?fabs(tol1):-fabs(tol1)); } - if( fabs(d)>=tol1) u=x+d; else u=x+(d>=0?fabs(tol1):-fabs(tol1)); - fu=(myclass_func.*eng)(u); - if( fu <= fx ){ - if( u >= x ) a=x; else b=x; - v=w; fv=fw; - w=x; fw=fx; - x=u; fx=fu; - } else { - if( u < x ) a=u; else b=u; - if( fu <=fw || w==x ){ - v=w; w=u; fv=fw; fw=fu; - } else if( fu <= fv || v==x || v==w ){ - v=u; fv=fu; - } + } else { + d=CGOLD*(e=( x >= xm ? a-x : b-x )); + } + if( fabs(d)>=tol1) u=x+d; else u=x+(d>=0?fabs(tol1):-fabs(tol1)); + fu=(myclass_func.*eng)(u); + if( fu <= fx ) { + if( u >= x ) a=x; else b=x; + v=w; fv=fw; + w=x; fw=fx; + x=u; fx=fu; + } else { + if( u < x ) a=u; else b=u; + if( fu <=fw || w==x ) { + v=w; w=u; fv=fw; fw=fu; + } else if( fu <= fv || v==x || v==w ) { + v=u; fv=fu; } - } - plumed_merror("Too many interactions in brent"); + } + } + plumed_merror("Too many interactions in brent"); } template <class FCLASS> diff --git a/src/tools/MinimiseBase.h b/src/tools/MinimiseBase.h index 80cfcc02e..27714da7c 100644 --- a/src/tools/MinimiseBase.h +++ b/src/tools/MinimiseBase.h @@ -47,7 +47,7 @@ private: engf_pointer calc; /// Member of class that calcualtes the energy we are trying to minimise engfnc_pointer calc2; -public: +public: explicit F1dim( const std::vector<double>& pp, const std::vector<double>& dd, FCLASS* ff, engf_pointer cc, engfnc_pointer cc2 ); /// Calculate the energy at \f$\mathbf{p} + xt*\mathbf{dir}\f$ double getEng( const double& xt ); @@ -55,21 +55,21 @@ public: template <class FCLASS> F1dim<FCLASS>::F1dim( const std::vector<double>& pp, const std::vector<double>& dd, FCLASS* ff, engf_pointer cc, engfnc_pointer cc2 ): -p(pp), -dir(dd), -pt(pp.size()), -fake_der(pp.size()), -func(ff), -calc(cc), -calc2(cc2) + p(pp), + dir(dd), + pt(pp.size()), + fake_der(pp.size()), + func(ff), + calc(cc), + calc2(cc2) { plumed_assert( calc || calc2 ); } template <class FCLASS> -double F1dim<FCLASS>::getEng( const double& xt ){ - for(unsigned j=0;j<pt.size();++j) pt[j] = p[j] + xt*dir[j]; - if( calc ) return (func->*calc)(pt,fake_der); +double F1dim<FCLASS>::getEng( const double& xt ) { + for(unsigned j=0; j<pt.size(); ++j) pt[j] = p[j] + xt*dir[j]; + if( calc ) return (func->*calc)(pt,fake_der); return (func->*calc2)(pt,fake_der); } @@ -82,7 +82,7 @@ private: /// The class that calculates the energy given a position FCLASS* myclass_func; protected: -/// This calculates the derivatives at a point +/// This calculates the derivatives at a point double calcDerivatives( const std::vector<double>& p, std::vector<double>& der, engf_pointer myfunc ); public: explicit MinimiseBase( FCLASS* funcc ) : myclass_func(funcc) {} @@ -91,8 +91,8 @@ public: }; template <class FCLASS> -double MinimiseBase<FCLASS>::linemin( const std::vector<double>& dir, std::vector<double>& p, engf_pointer myfunc ){ - // Construct the object that turns points on a line into vectors +double MinimiseBase<FCLASS>::linemin( const std::vector<double>& dir, std::vector<double>& p, engf_pointer myfunc ) { + // Construct the object that turns points on a line into vectors F1dim<FCLASS> f1dim( p, dir, myclass_func, NULL, myfunc ); // Construct an object that will do the line search for the minimum @@ -100,14 +100,14 @@ double MinimiseBase<FCLASS>::linemin( const std::vector<double>& dir, std::vecto // This does the actual line minimisation double ax=0.0, xx=1.0; - bb.bracket( ax, xx, &F1dim<FCLASS>::getEng ); + bb.bracket( ax, xx, &F1dim<FCLASS>::getEng ); double xmin=bb.minimise( &F1dim<FCLASS>::getEng ); - for(unsigned i=0;i<p.size();++i) p[i] += xmin*dir[i]; + for(unsigned i=0; i<p.size(); ++i) p[i] += xmin*dir[i]; return bb.getMinimumValue(); } template <class FCLASS> -double MinimiseBase<FCLASS>::calcDerivatives( const std::vector<double>& p, std::vector<double>& der, engf_pointer myfunc ){ +double MinimiseBase<FCLASS>::calcDerivatives( const std::vector<double>& p, std::vector<double>& der, engf_pointer myfunc ) { return (myclass_func->*myfunc)( p, der ); } diff --git a/src/tools/MolDataClass.cpp b/src/tools/MolDataClass.cpp index 49f0e0fac..310267d5a 100644 --- a/src/tools/MolDataClass.cpp +++ b/src/tools/MolDataClass.cpp @@ -26,156 +26,156 @@ namespace PLMD { -unsigned MolDataClass::numberOfAtomsPerResidueInBackbone( const std::string& type ){ +unsigned MolDataClass::numberOfAtomsPerResidueInBackbone( const std::string& type ) { if( type=="protein" ) return 5; else if( type=="dna" ) return 6; - else if( type=="rna" ) return 6; + else if( type=="rna" ) return 6; else return 0; } -bool MolDataClass::allowedResidue( const std::string& type, const std::string& residuename ){ - if( type=="protein" ){ - if(residuename=="ALA") return true; - else if(residuename=="ARG") return true; - else if(residuename=="ASN") return true; - else if(residuename=="ASP") return true; - else if(residuename=="CYS") return true; - else if(residuename=="GLN") return true; - else if(residuename=="GLU") return true; - else if(residuename=="GLY") return true; - else if(residuename=="HIS") return true; - else if(residuename=="ILE") return true; - else if(residuename=="LEU") return true; - else if(residuename=="LYS") return true; - else if(residuename=="MET") return true; - else if(residuename=="PHE") return true; - else if(residuename=="PRO") return true; - else if(residuename=="SER") return true; - else if(residuename=="THR") return true; - else if(residuename=="TRP") return true; - else if(residuename=="TYR") return true; - else if(residuename=="VAL") return true; +bool MolDataClass::allowedResidue( const std::string& type, const std::string& residuename ) { + if( type=="protein" ) { + if(residuename=="ALA") return true; + else if(residuename=="ARG") return true; + else if(residuename=="ASN") return true; + else if(residuename=="ASP") return true; + else if(residuename=="CYS") return true; + else if(residuename=="GLN") return true; + else if(residuename=="GLU") return true; + else if(residuename=="GLY") return true; + else if(residuename=="HIS") return true; + else if(residuename=="ILE") return true; + else if(residuename=="LEU") return true; + else if(residuename=="LYS") return true; + else if(residuename=="MET") return true; + else if(residuename=="PHE") return true; + else if(residuename=="PRO") return true; + else if(residuename=="SER") return true; + else if(residuename=="THR") return true; + else if(residuename=="TRP") return true; + else if(residuename=="TYR") return true; + else if(residuename=="VAL") return true; // Terminal groups - else if(residuename=="ACE") return true; - else if(residuename=="NME") return true; -// Alternative residue names in common force fiels - else if(residuename=="GLH") return true; // neutral GLU - else if(residuename=="ASH") return true; // neutral ASP - else if(residuename=="HID") return true; // HIS-D amber - else if(residuename=="HSD") return true; // HIS-D charmm - else if(residuename=="HIE") return true; // HIS-E amber - else if(residuename=="HSE") return true; // HIS-E charmm - else if(residuename=="HIP") return true; // HIS-P amber - else if(residuename=="HSP") return true; // HIS-P charmm - else return false; - } else if( type=="dna" ){ - if(residuename=="DA") return true; - else if(residuename=="DG") return true; - else if(residuename=="DT") return true; - else if(residuename=="DC") return true; - else if(residuename=="DA5") return true; - else if(residuename=="DA3") return true; - else if(residuename=="DAN") return true; - else if(residuename=="DG5") return true; - else if(residuename=="DG3") return true; - else if(residuename=="DGN") return true; - else if(residuename=="DT5") return true; - else if(residuename=="DT3") return true; - else if(residuename=="DTN") return true; - else if(residuename=="DC5") return true; - else if(residuename=="DC3") return true; - else if(residuename=="DCN") return true; - else return false; - } else if( type=="rna" ){ - if(residuename=="A") return true; - else if(residuename=="A5") return true; - else if(residuename=="A3") return true; - else if(residuename=="AN") return true; - else if(residuename=="G") return true; - else if(residuename=="G5") return true; - else if(residuename=="G3") return true; - else if(residuename=="GN") return true; - else if(residuename=="U") return true; - else if(residuename=="U5") return true; - else if(residuename=="U3") return true; - else if(residuename=="UN") return true; - else if(residuename=="C") return true; - else if(residuename=="C5") return true; - else if(residuename=="C3") return true; - else if(residuename=="CN") return true; - else if(residuename=="RA") return true; - else if(residuename=="RA5") return true; - else if(residuename=="RA3") return true; - else if(residuename=="RAN") return true; - else if(residuename=="RG") return true; - else if(residuename=="RG5") return true; - else if(residuename=="RG3") return true; - else if(residuename=="RGN") return true; - else if(residuename=="RU") return true; - else if(residuename=="RU5") return true; - else if(residuename=="RU3") return true; - else if(residuename=="RUN") return true; - else if(residuename=="RC") return true; - else if(residuename=="RC5") return true; - else if(residuename=="RC3") return true; - else if(residuename=="RCN") return true; - else return false; - } + else if(residuename=="ACE") return true; + else if(residuename=="NME") return true; +// Alternative residue names in common force fiels + else if(residuename=="GLH") return true; // neutral GLU + else if(residuename=="ASH") return true; // neutral ASP + else if(residuename=="HID") return true; // HIS-D amber + else if(residuename=="HSD") return true; // HIS-D charmm + else if(residuename=="HIE") return true; // HIS-E amber + else if(residuename=="HSE") return true; // HIS-E charmm + else if(residuename=="HIP") return true; // HIS-P amber + else if(residuename=="HSP") return true; // HIS-P charmm + else return false; + } else if( type=="dna" ) { + if(residuename=="DA") return true; + else if(residuename=="DG") return true; + else if(residuename=="DT") return true; + else if(residuename=="DC") return true; + else if(residuename=="DA5") return true; + else if(residuename=="DA3") return true; + else if(residuename=="DAN") return true; + else if(residuename=="DG5") return true; + else if(residuename=="DG3") return true; + else if(residuename=="DGN") return true; + else if(residuename=="DT5") return true; + else if(residuename=="DT3") return true; + else if(residuename=="DTN") return true; + else if(residuename=="DC5") return true; + else if(residuename=="DC3") return true; + else if(residuename=="DCN") return true; + else return false; + } else if( type=="rna" ) { + if(residuename=="A") return true; + else if(residuename=="A5") return true; + else if(residuename=="A3") return true; + else if(residuename=="AN") return true; + else if(residuename=="G") return true; + else if(residuename=="G5") return true; + else if(residuename=="G3") return true; + else if(residuename=="GN") return true; + else if(residuename=="U") return true; + else if(residuename=="U5") return true; + else if(residuename=="U3") return true; + else if(residuename=="UN") return true; + else if(residuename=="C") return true; + else if(residuename=="C5") return true; + else if(residuename=="C3") return true; + else if(residuename=="CN") return true; + else if(residuename=="RA") return true; + else if(residuename=="RA5") return true; + else if(residuename=="RA3") return true; + else if(residuename=="RAN") return true; + else if(residuename=="RG") return true; + else if(residuename=="RG5") return true; + else if(residuename=="RG3") return true; + else if(residuename=="RGN") return true; + else if(residuename=="RU") return true; + else if(residuename=="RU5") return true; + else if(residuename=="RU3") return true; + else if(residuename=="RUN") return true; + else if(residuename=="RC") return true; + else if(residuename=="RC5") return true; + else if(residuename=="RC3") return true; + else if(residuename=="RCN") return true; + else return false; + } return false; } -void MolDataClass::getBackboneForResidue( const std::string& type, const unsigned& residuenum, const PDB& mypdb, std::vector<AtomNumber>& atoms ){ +void MolDataClass::getBackboneForResidue( const std::string& type, const unsigned& residuenum, const PDB& mypdb, std::vector<AtomNumber>& atoms ) { std::string residuename=mypdb.getResidueName( residuenum ); plumed_massert( MolDataClass::allowedResidue( type, residuename ), "residue " + residuename + " unrecognized for molecule type " + type ); - if( type=="protein" ){ - if( residuename=="GLY"){ - atoms.resize(5); - atoms[0]=mypdb.getNamedAtomFromResidue("N",residuenum); - atoms[1]=mypdb.getNamedAtomFromResidue("CA",residuenum); - atoms[2]=mypdb.getNamedAtomFromResidue("HA1",residuenum); - atoms[3]=mypdb.getNamedAtomFromResidue("C",residuenum); - atoms[4]=mypdb.getNamedAtomFromResidue("O",residuenum); - } else if( residuename=="ACE"){ - atoms.resize(1); - atoms[0]=mypdb.getNamedAtomFromResidue("C",residuenum); - } else if( residuename=="NME"){ - atoms.resize(1); - atoms[0]=mypdb.getNamedAtomFromResidue("N",residuenum); - } else { - atoms.resize(5); - atoms[0]=mypdb.getNamedAtomFromResidue("N",residuenum); - atoms[1]=mypdb.getNamedAtomFromResidue("CA",residuenum); - atoms[2]=mypdb.getNamedAtomFromResidue("CB",residuenum); - atoms[3]=mypdb.getNamedAtomFromResidue("C",residuenum); - atoms[4]=mypdb.getNamedAtomFromResidue("O",residuenum); - } - } else if( type=="dna" || type=="rna" ){ - atoms.resize(6); - atoms[0]=mypdb.getNamedAtomFromResidue("P",residuenum); - atoms[1]=mypdb.getNamedAtomFromResidue("O5\'",residuenum); - atoms[2]=mypdb.getNamedAtomFromResidue("C5\'",residuenum); - atoms[3]=mypdb.getNamedAtomFromResidue("C4\'",residuenum); - atoms[4]=mypdb.getNamedAtomFromResidue("C3\'",residuenum); - atoms[5]=mypdb.getNamedAtomFromResidue("O3\'",residuenum); - } + if( type=="protein" ) { + if( residuename=="GLY") { + atoms.resize(5); + atoms[0]=mypdb.getNamedAtomFromResidue("N",residuenum); + atoms[1]=mypdb.getNamedAtomFromResidue("CA",residuenum); + atoms[2]=mypdb.getNamedAtomFromResidue("HA1",residuenum); + atoms[3]=mypdb.getNamedAtomFromResidue("C",residuenum); + atoms[4]=mypdb.getNamedAtomFromResidue("O",residuenum); + } else if( residuename=="ACE") { + atoms.resize(1); + atoms[0]=mypdb.getNamedAtomFromResidue("C",residuenum); + } else if( residuename=="NME") { + atoms.resize(1); + atoms[0]=mypdb.getNamedAtomFromResidue("N",residuenum); + } else { + atoms.resize(5); + atoms[0]=mypdb.getNamedAtomFromResidue("N",residuenum); + atoms[1]=mypdb.getNamedAtomFromResidue("CA",residuenum); + atoms[2]=mypdb.getNamedAtomFromResidue("CB",residuenum); + atoms[3]=mypdb.getNamedAtomFromResidue("C",residuenum); + atoms[4]=mypdb.getNamedAtomFromResidue("O",residuenum); + } + } else if( type=="dna" || type=="rna" ) { + atoms.resize(6); + atoms[0]=mypdb.getNamedAtomFromResidue("P",residuenum); + atoms[1]=mypdb.getNamedAtomFromResidue("O5\'",residuenum); + atoms[2]=mypdb.getNamedAtomFromResidue("C5\'",residuenum); + atoms[3]=mypdb.getNamedAtomFromResidue("C4\'",residuenum); + atoms[4]=mypdb.getNamedAtomFromResidue("C3\'",residuenum); + atoms[5]=mypdb.getNamedAtomFromResidue("O3\'",residuenum); + } else { - plumed_merror(type + " is not a valid molecule type"); + plumed_merror(type + " is not a valid molecule type"); } } -bool MolDataClass::isTerminalGroup( const std::string& type, const std::string& residuename ){ - if( type=="protein" ){ - if( residuename=="ACE" ) return true; - else if( residuename=="NME" ) return true; - else return false; +bool MolDataClass::isTerminalGroup( const std::string& type, const std::string& residuename ) { + if( type=="protein" ) { + if( residuename=="ACE" ) return true; + else if( residuename=="NME" ) return true; + else return false; } else { - plumed_merror(type + " is not a valid molecule type"); - } + plumed_merror(type + " is not a valid molecule type"); + } return false; } -void MolDataClass::specialSymbol( const std::string& type, const std::string& symbol, const PDB& mypdb, std::vector<AtomNumber>& numbers ){ - if(type=="protein" || type=="rna" || type=="dna"){ +void MolDataClass::specialSymbol( const std::string& type, const std::string& symbol, const PDB& mypdb, std::vector<AtomNumber>& numbers ) { + if(type=="protein" || type=="rna" || type=="dna") { // symbol should be something like // phi-123 i.e. phi torsion of residue 123 of first chain // psi-A321 i.e. psi torsion of residue 321 of chain A @@ -186,7 +186,7 @@ void MolDataClass::specialSymbol( const std::string& type, const std::string& sy unsigned resnum; std::string resname; std::string chainid; - if(firstnum==dash+1){ + if(firstnum==dash+1) { Tools::convert( symbol.substr(dash+1), resnum ); resname= mypdb.getResidueName(resnum); chainid="*"; // this is going to match the first chain @@ -197,23 +197,23 @@ void MolDataClass::specialSymbol( const std::string& type, const std::string& sy } resname= mypdb.getResidueName(resnum,chainid); Tools::stripLeadingAndTrailingBlanks(resname); - if(allowedResidue("protein",resname)){ - if( name=="phi" && !isTerminalGroup("protein",resname) ){ + if(allowedResidue("protein",resname)) { + if( name=="phi" && !isTerminalGroup("protein",resname) ) { numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C",resnum-1,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("N",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("CA",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C",resnum,chainid)); - } else if( name=="psi" && !isTerminalGroup("protein",resname) ){ + } else if( name=="psi" && !isTerminalGroup("protein",resname) ) { numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("N",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("CA",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("N",resnum+1,chainid)); - } else if( name=="omega" && !isTerminalGroup("protein",resname) ){ + } else if( name=="omega" && !isTerminalGroup("protein",resname) ) { numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("CA",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("N",resnum+1,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("CA",resnum+1,chainid)); - } else if( name=="chi1" && !isTerminalGroup("protein",resname) ){ + } else if( name=="chi1" && !isTerminalGroup("protein",resname) ) { if ( resname=="GLY" || resname=="ALA" ) plumed_merror("chi-1 is not defined for Alanine and Glycine"); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("N",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("CA",resnum,chainid)); @@ -229,7 +229,7 @@ void MolDataClass::specialSymbol( const std::string& type, const std::string& sy else numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("CG",resnum,chainid)); } else numbers.push_back(mypdb.getNamedAtomFromResidueAndChain(name,resnum,chainid)); - } else if( allowedResidue("rna",resname) || allowedResidue("dna",resname)){ + } else if( allowedResidue("rna",resname) || allowedResidue("dna",resname)) { std::string basetype; if(resname.find_first_of("A")!=std::string::npos) basetype+="A"; if(resname.find_first_of("U")!=std::string::npos) basetype+="U"; @@ -240,10 +240,10 @@ void MolDataClass::specialSymbol( const std::string& type, const std::string& sy if( name=="chi" ) { numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("O4\'",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C1\'",resnum,chainid)); - if(basetype=="T" || basetype=="U" || basetype=="C"){ + if(basetype=="T" || basetype=="U" || basetype=="C") { numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("N1",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C2",resnum,chainid)); - } else if(basetype=="G" || basetype=="A"){ + } else if(basetype=="G" || basetype=="A") { numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("N9",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C4",resnum,chainid)); } else plumed_error(); @@ -316,7 +316,7 @@ void MolDataClass::specialSymbol( const std::string& type, const std::string& sy numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C2\'",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C3\'",resnum,chainid)); } else if( name=="base" ) { - if(basetype=="C"){ + if(basetype=="C") { numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("N1",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C2",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("O2",resnum,chainid)); @@ -325,7 +325,7 @@ void MolDataClass::specialSymbol( const std::string& type, const std::string& sy numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("N4",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C5",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C6",resnum,chainid)); - } else if(basetype=="U"){ + } else if(basetype=="U") { numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("N1",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C2",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("O2",resnum,chainid)); @@ -334,7 +334,7 @@ void MolDataClass::specialSymbol( const std::string& type, const std::string& sy numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("O4",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C5",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C6",resnum,chainid)); - } else if(basetype=="T"){ + } else if(basetype=="T") { numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("N1",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C2",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("O2",resnum,chainid)); @@ -344,7 +344,7 @@ void MolDataClass::specialSymbol( const std::string& type, const std::string& sy numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C5",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C7",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C6",resnum,chainid)); - } else if(basetype=="G"){ + } else if(basetype=="G") { numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("N9",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C4",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("N3",resnum,chainid)); @@ -356,7 +356,7 @@ void MolDataClass::specialSymbol( const std::string& type, const std::string& sy numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C5",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("N7",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C8",resnum,chainid)); - } else if(basetype=="A"){ + } else if(basetype=="A") { numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("N9",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C4",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("N1",resnum,chainid)); @@ -370,19 +370,19 @@ void MolDataClass::specialSymbol( const std::string& type, const std::string& sy } else plumed_error(); } else if( name=="lcs" ) { numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C2",resnum,chainid)); - if(basetype=="T" || basetype=="U" || basetype=="C"){ + if(basetype=="T" || basetype=="U" || basetype=="C") { numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C4",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C6",resnum,chainid)); - } else if(basetype=="G" || basetype=="A"){ + } else if(basetype=="G" || basetype=="A") { numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C6",resnum,chainid)); numbers.push_back(mypdb.getNamedAtomFromResidueAndChain("C4",resnum,chainid)); - } else plumed_error(); + } else plumed_error(); } else numbers.push_back(mypdb.getNamedAtomFromResidueAndChain(name,resnum,chainid)); } } else { - plumed_merror(type + " is not a valid molecule type"); + plumed_merror(type + " is not a valid molecule type"); } -} +} } diff --git a/src/tools/MolDataClass.h b/src/tools/MolDataClass.h index 7ffb6c425..e3ee32335 100644 --- a/src/tools/MolDataClass.h +++ b/src/tools/MolDataClass.h @@ -26,12 +26,12 @@ #include <string> #include "AtomNumber.h" -namespace PLMD{ +namespace PLMD { class PDB; /// This class provides information on various kinds of molecules -/// for instance the kinds of residues that are in a protein +/// for instance the kinds of residues that are in a protein /// the atoms involved in the backbone of a particular residue etc class MolDataClass { public: @@ -40,7 +40,7 @@ public: /// Return the number of atoms in the backbone per residue e.g. 5 for proteins static unsigned numberOfAtomsPerResidueInBackbone( const std::string& type ); /// Return the names of the atoms in the backbone e.g. N, CA, CB, C, O for most protein residues - static void getBackboneForResidue( const std::string& type, const unsigned& residuenum, const PDB& mypdb, std::vector<AtomNumber>& atoms ); + static void getBackboneForResidue( const std::string& type, const unsigned& residuenum, const PDB& mypdb, std::vector<AtomNumber>& atoms ); /// Return true if the residue is a terminal group e.g. ACE, NME for proteins static bool isTerminalGroup( const std::string& type, const std::string& residuename ); /// Used to interpret special symbols - currently phi and psi and omega diff --git a/src/tools/MultiValue.cpp b/src/tools/MultiValue.cpp index 80a8f6b86..cdf242165 100644 --- a/src/tools/MultiValue.cpp +++ b/src/tools/MultiValue.cpp @@ -21,98 +21,98 @@ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ #include "MultiValue.h" -namespace PLMD{ +namespace PLMD { MultiValue::MultiValue( const unsigned& nvals, const unsigned& nder ): -values(nvals), -nderivatives(nder), -derivatives(nvals*nder), -tmpval(0), -tmpder(nder), -atLeastOneSet(false) + values(nvals), + nderivatives(nder), + derivatives(nvals*nder), + tmpval(0), + tmpder(nder), + atLeastOneSet(false) { std::vector<unsigned> myind( nder ); - for(unsigned i=0;i<nder;++i) myind[i]=i; - hasDerivatives.createIndexListFromVector( myind ); + for(unsigned i=0; i<nder; ++i) myind[i]=i; + hasDerivatives.createIndexListFromVector( myind ); } -void MultiValue::resize( const unsigned& nvals, const unsigned& nder ){ +void MultiValue::resize( const unsigned& nvals, const unsigned& nder ) { values.resize(nvals); nderivatives=nder; derivatives.resize( nvals*nder ); - tmpder.resize( nder ); hasDerivatives.clear(); std::vector<unsigned> myind( nder ); - for(unsigned i=0;i<nder;++i) myind[i]=i; + tmpder.resize( nder ); hasDerivatives.clear(); std::vector<unsigned> myind( nder ); + for(unsigned i=0; i<nder; ++i) myind[i]=i; hasDerivatives.createIndexListFromVector( myind ); atLeastOneSet=false; } -void MultiValue::clearAll(){ +void MultiValue::clearAll() { if( atLeastOneSet && !hasDerivatives.updateComplete() ) hasDerivatives.updateActiveMembers(); - for(unsigned i=0;i<values.size();++i) clear(i); + for(unsigned i=0; i<values.size(); ++i) clear(i); clearTemporyDerivatives(); hasDerivatives.deactivateAll(); atLeastOneSet=false; } -void MultiValue::clear( const unsigned& ival ){ +void MultiValue::clear( const unsigned& ival ) { values[ival]=0; unsigned base=ival*nderivatives, ndert=hasDerivatives.getNumberActive(); - for(unsigned i=0;i<ndert;++i) derivatives[ base+hasDerivatives[i] ]=0.; + for(unsigned i=0; i<ndert; ++i) derivatives[ base+hasDerivatives[i] ]=0.; } -void MultiValue::clearTemporyDerivatives(){ +void MultiValue::clearTemporyDerivatives() { unsigned ndert=hasDerivatives.getNumberActive(); tmpval=0.; - for(unsigned i=0;i<ndert;++i) tmpder[ hasDerivatives[i] ]=0.; + for(unsigned i=0; i<ndert; ++i) tmpder[ hasDerivatives[i] ]=0.; } -void MultiValue::chainRule( const unsigned& ival, const unsigned& iout, const unsigned& stride, const unsigned& off, - const double& df, const unsigned& bufstart, std::vector<double>& buffer ){ +void MultiValue::chainRule( const unsigned& ival, const unsigned& iout, const unsigned& stride, const unsigned& off, + const double& df, const unsigned& bufstart, std::vector<double>& buffer ) { if( !hasDerivatives.updateComplete() ) hasDerivatives.updateActiveMembers(); plumed_dbg_assert( off<stride ); unsigned base=nderivatives*ival, ndert=hasDerivatives.getNumberActive(); - unsigned start=bufstart+stride*(nderivatives+1)*iout + stride; - for(unsigned i=0;i<ndert;++i){ - unsigned jder=hasDerivatives[i]; - buffer[start+jder*stride] += df*derivatives[base+jder]; + unsigned start=bufstart+stride*(nderivatives+1)*iout + stride; + for(unsigned i=0; i<ndert; ++i) { + unsigned jder=hasDerivatives[i]; + buffer[start+jder*stride] += df*derivatives[base+jder]; } } -void MultiValue::copyValues( MultiValue& outvals ) const { +void MultiValue::copyValues( MultiValue& outvals ) const { plumed_dbg_assert( values.size()<=outvals.getNumberOfValues() ); - for(unsigned i=0;i<values.size();++i) outvals.setValue( i, values[i] ); - + for(unsigned i=0; i<values.size(); ++i) outvals.setValue( i, values[i] ); + } -void MultiValue::copyDerivatives( MultiValue& outvals ){ +void MultiValue::copyDerivatives( MultiValue& outvals ) { plumed_dbg_assert( values.size()<=outvals.getNumberOfValues() && nderivatives<=outvals.getNumberOfDerivatives() ); if( !hasDerivatives.updateComplete() ) hasDerivatives.updateActiveMembers(); outvals.atLeastOneSet=true; unsigned ndert=hasDerivatives.getNumberActive(); - for(unsigned j=0;j<ndert;++j){ - unsigned jder=hasDerivatives[j]; outvals.hasDerivatives.activate(jder); + for(unsigned j=0; j<ndert; ++j) { + unsigned jder=hasDerivatives[j]; outvals.hasDerivatives.activate(jder); } - + unsigned base=0, obase=0; - for(unsigned i=0;i<values.size();++i){ - for(unsigned j=0;j<ndert;++j){ - unsigned jder=hasDerivatives[j]; - outvals.derivatives[obase+jder] += derivatives[base+jder]; - } - obase+=outvals.nderivatives; base+=nderivatives; + for(unsigned i=0; i<values.size(); ++i) { + for(unsigned j=0; j<ndert; ++j) { + unsigned jder=hasDerivatives[j]; + outvals.derivatives[obase+jder] += derivatives[base+jder]; + } + obase+=outvals.nderivatives; base+=nderivatives; } } -void MultiValue::quotientRule( const unsigned& nder, const unsigned& oder ){ +void MultiValue::quotientRule( const unsigned& nder, const unsigned& oder ) { plumed_dbg_assert( nder<values.size() && oder<values.size() ); if( !hasDerivatives.updateComplete() ) hasDerivatives.updateActiveMembers(); unsigned ndert=hasDerivatives.getNumberActive(); double wpref; unsigned obase=oder*nderivatives, nbase=nder*nderivatives; - if( fabs(tmpval)>epsilon ){ wpref=1.0/tmpval; } - else{ wpref=1.0; } + if( fabs(tmpval)>epsilon ) { wpref=1.0/tmpval; } + else { wpref=1.0; } double pref = values[nder]*wpref*wpref; - for(unsigned j=0;j<ndert;++j){ - unsigned jder=hasDerivatives[j]; - derivatives[obase+jder] = wpref*derivatives[nbase+jder] - pref*tmpder[jder]; + for(unsigned j=0; j<ndert; ++j) { + unsigned jder=hasDerivatives[j]; + derivatives[obase+jder] = wpref*derivatives[nbase+jder] - pref*tmpder[jder]; } values[oder] = wpref*values[nder]; } diff --git a/src/tools/MultiValue.h b/src/tools/MultiValue.h index 5e2f2ce59..5f5f6ec64 100644 --- a/src/tools/MultiValue.h +++ b/src/tools/MultiValue.h @@ -26,7 +26,7 @@ #include "Exception.h" #include "DynamicList.h" -namespace PLMD{ +namespace PLMD { class MultiValue { private: @@ -48,14 +48,14 @@ private: std::vector<unsigned> indices, sort_indices; std::vector<Vector> tmp_atoms; public: - MultiValue( const unsigned& , const unsigned& ); - void resize( const unsigned& , const unsigned& ); + MultiValue( const unsigned&, const unsigned& ); + void resize( const unsigned&, const unsigned& ); /// std::vector<unsigned>& getIndices(); std::vector<unsigned>& getSortIndices(); std::vector<Vector>& getAtomVector(); /// Get the number of values in the stash - unsigned getNumberOfValues() const ; + unsigned getNumberOfValues() const ; /// Get the number of derivatives in the stash unsigned getNumberOfDerivatives() const ; /// Set value numbered @@ -63,7 +63,7 @@ public: /// Add value numbered void addValue( const unsigned&, const double& ); /// Add derivative - void addDerivative( const unsigned& , const unsigned& , const double& ); + void addDerivative( const unsigned&, const unsigned&, const double& ); /// Add to the tempory value void addTemporyValue( const double& val ); /// Add tempory derivatives - this is used for calculating quotients @@ -75,7 +75,7 @@ public: /// Return a derivative value double getDerivative( const unsigned&, const unsigned& ) const ; /// Get one of the tempory derivatives - double getTemporyDerivative( const unsigned& jder ) const ; + double getTemporyDerivative( const unsigned& jder ) const ; /// Clear all values void clearAll(); /// Clear the tempory derivatives @@ -96,7 +96,7 @@ public: /// unsigned getActiveIndex( const unsigned& ) const ; /// Transfer derivatives to buffer - void chainRule( const unsigned& , const unsigned& , const unsigned&, const unsigned& , const double& , const unsigned& , std::vector<double>& buffer ); + void chainRule( const unsigned&, const unsigned&, const unsigned&, const unsigned&, const double&, const unsigned&, std::vector<double>& buffer ); /// void copyValues( MultiValue& ) const ; /// @@ -122,37 +122,37 @@ double MultiValue::get( const unsigned& ival ) const { } inline -void MultiValue::setValue( const unsigned& ival, const double& val){ +void MultiValue::setValue( const unsigned& ival, const double& val) { plumed_dbg_assert( ival<=values.size() ); values[ival]=val; } inline -void MultiValue::addValue( const unsigned& ival, const double& val){ +void MultiValue::addValue( const unsigned& ival, const double& val) { plumed_dbg_assert( ival<=values.size() ); values[ival]+=val; } inline -void MultiValue::addDerivative( const unsigned& ival, const unsigned& jder, const double& der){ +void MultiValue::addDerivative( const unsigned& ival, const unsigned& jder, const double& der) { plumed_dbg_assert( ival<=values.size() && jder<nderivatives ); atLeastOneSet=true; hasDerivatives.activate(jder); derivatives[nderivatives*ival+jder] += der; } inline -void MultiValue::addTemporyValue( const double& val ){ +void MultiValue::addTemporyValue( const double& val ) { tmpval += val; } inline -void MultiValue::addTemporyDerivative( const unsigned& jder, const double& der ){ +void MultiValue::addTemporyDerivative( const unsigned& jder, const double& der ) { plumed_dbg_assert( jder<nderivatives ); atLeastOneSet=true; hasDerivatives.activate(jder); tmpder[jder] += der; } inline -void MultiValue::setDerivative( const unsigned& ival, const unsigned& jder, const double& der){ +void MultiValue::setDerivative( const unsigned& ival, const unsigned& jder, const double& der) { plumed_dbg_assert( ival<=values.size() && jder<nderivatives ); atLeastOneSet=true; hasDerivatives.activate(jder); derivatives[nderivatives*ival+jder]=der; } @@ -171,32 +171,32 @@ double MultiValue::getTemporyDerivative( const unsigned& jder ) const { } inline -bool MultiValue::updateComplete(){ +bool MultiValue::updateComplete() { return hasDerivatives.updateComplete(); } inline -void MultiValue::emptyActiveMembers(){ +void MultiValue::emptyActiveMembers() { hasDerivatives.emptyActiveMembers(); } inline -void MultiValue::putIndexInActiveArray( const unsigned& ind ){ +void MultiValue::putIndexInActiveArray( const unsigned& ind ) { hasDerivatives.putIndexInActiveArray( ind ); } inline -void MultiValue::updateIndex( const unsigned& ind ){ +void MultiValue::updateIndex( const unsigned& ind ) { if( hasDerivatives.isActive(ind) ) hasDerivatives.putIndexInActiveArray( ind ); } inline -void MultiValue::sortActiveList(){ +void MultiValue::sortActiveList() { hasDerivatives.sortActiveList(); } inline -void MultiValue::completeUpdate(){ +void MultiValue::completeUpdate() { hasDerivatives.completeUpdate(); } @@ -212,22 +212,22 @@ unsigned MultiValue::getActiveIndex( const unsigned& ind ) const { } inline -void MultiValue::updateDynamicList(){ +void MultiValue::updateDynamicList() { if( atLeastOneSet ) hasDerivatives.updateActiveMembers(); } inline -std::vector<unsigned>& MultiValue::getIndices(){ +std::vector<unsigned>& MultiValue::getIndices() { return indices; } inline -std::vector<unsigned>& MultiValue::getSortIndices(){ +std::vector<unsigned>& MultiValue::getSortIndices() { return sort_indices; } inline -std::vector<Vector>& MultiValue::getAtomVector(){ +std::vector<Vector>& MultiValue::getAtomVector() { return tmp_atoms; } diff --git a/src/tools/NeighborList.cpp b/src/tools/NeighborList.cpp index 038aefd70..8ce8fafd7 100644 --- a/src/tools/NeighborList.cpp +++ b/src/tools/NeighborList.cpp @@ -27,142 +27,142 @@ #include <vector> #include <algorithm> -namespace PLMD{ +namespace PLMD { using namespace std; NeighborList::NeighborList(const vector<AtomNumber>& list0, const vector<AtomNumber>& list1, const bool& do_pair, const bool& do_pbc, const Pbc& pbc, const double& distance, const unsigned& stride): reduced(false), - do_pair_(do_pair), do_pbc_(do_pbc), pbc_(&pbc), - distance_(distance), stride_(stride) + do_pair_(do_pair), do_pbc_(do_pbc), pbc_(&pbc), + distance_(distance), stride_(stride) { // store full list of atoms needed - fullatomlist_=list0; - fullatomlist_.insert(fullatomlist_.end(),list1.begin(),list1.end()); - nlist0_=list0.size(); - nlist1_=list1.size(); - twolists_=true; - if(!do_pair){ - nallpairs_=nlist0_*nlist1_; - }else{ - plumed_assert(nlist0_==nlist1_); - nallpairs_=nlist0_; - } - initialize(); - lastupdate_=0; + fullatomlist_=list0; + fullatomlist_.insert(fullatomlist_.end(),list1.begin(),list1.end()); + nlist0_=list0.size(); + nlist1_=list1.size(); + twolists_=true; + if(!do_pair) { + nallpairs_=nlist0_*nlist1_; + } else { + plumed_assert(nlist0_==nlist1_); + nallpairs_=nlist0_; + } + initialize(); + lastupdate_=0; } NeighborList::NeighborList(const vector<AtomNumber>& list0, const bool& do_pbc, const Pbc& pbc, const double& distance, const unsigned& stride): reduced(false), - do_pbc_(do_pbc), pbc_(&pbc), - distance_(distance), stride_(stride){ - fullatomlist_=list0; - nlist0_=list0.size(); - twolists_=false; - nallpairs_=nlist0_*(nlist0_-1)/2; - initialize(); - lastupdate_=0; + do_pbc_(do_pbc), pbc_(&pbc), + distance_(distance), stride_(stride) { + fullatomlist_=list0; + nlist0_=list0.size(); + twolists_=false; + nallpairs_=nlist0_*(nlist0_-1)/2; + initialize(); + lastupdate_=0; } void NeighborList::initialize() { - neighbors_.clear(); - for(unsigned int i=0;i<nallpairs_;++i){ - neighbors_.push_back(getIndexPair(i)); - } + neighbors_.clear(); + for(unsigned int i=0; i<nallpairs_; ++i) { + neighbors_.push_back(getIndexPair(i)); + } } vector<AtomNumber>& NeighborList::getFullAtomList() { - return fullatomlist_; + return fullatomlist_; } pair<unsigned,unsigned> NeighborList::getIndexPair(unsigned ipair) { - pair<unsigned,unsigned> index; - if(twolists_ && do_pair_){ - index=pair<unsigned,unsigned>(ipair,ipair+nlist0_); - }else if (twolists_ && !do_pair_){ - index=pair<unsigned,unsigned>(ipair/nlist1_,ipair%nlist1_+nlist0_); - }else if (!twolists_){ - unsigned ii = nallpairs_-1-ipair; - unsigned K = unsigned(floor((sqrt(double(8*ii+1))+1)/2)); - unsigned jj = ii-K*(K-1)/2; - index=pair<unsigned,unsigned>(nlist0_-1-K,nlist0_-1-jj); - } - return index; + pair<unsigned,unsigned> index; + if(twolists_ && do_pair_) { + index=pair<unsigned,unsigned>(ipair,ipair+nlist0_); + } else if (twolists_ && !do_pair_) { + index=pair<unsigned,unsigned>(ipair/nlist1_,ipair%nlist1_+nlist0_); + } else if (!twolists_) { + unsigned ii = nallpairs_-1-ipair; + unsigned K = unsigned(floor((sqrt(double(8*ii+1))+1)/2)); + unsigned jj = ii-K*(K-1)/2; + index=pair<unsigned,unsigned>(nlist0_-1-K,nlist0_-1-jj); + } + return index; } void NeighborList::update(const vector<Vector>& positions) { - neighbors_.clear(); - const double d2=distance_*distance_; -// check if positions array has the correct length - plumed_assert(positions.size()==fullatomlist_.size()); - for(unsigned int i=0;i<nallpairs_;++i){ - pair<unsigned,unsigned> index=getIndexPair(i); - unsigned index0=index.first; - unsigned index1=index.second; - Vector distance; - if(do_pbc_){ - distance=pbc_->distance(positions[index0],positions[index1]); - } else { - distance=delta(positions[index0],positions[index1]); - } - double value=modulo2(distance); - if(value<=d2) {neighbors_.push_back(index);} - } - setRequestList(); + neighbors_.clear(); + const double d2=distance_*distance_; +// check if positions array has the correct length + plumed_assert(positions.size()==fullatomlist_.size()); + for(unsigned int i=0; i<nallpairs_; ++i) { + pair<unsigned,unsigned> index=getIndexPair(i); + unsigned index0=index.first; + unsigned index1=index.second; + Vector distance; + if(do_pbc_) { + distance=pbc_->distance(positions[index0],positions[index1]); + } else { + distance=delta(positions[index0],positions[index1]); + } + double value=modulo2(distance); + if(value<=d2) {neighbors_.push_back(index);} + } + setRequestList(); } void NeighborList::setRequestList() { - requestlist_.clear(); - for(unsigned int i=0;i<size();++i){ - requestlist_.push_back(fullatomlist_[neighbors_[i].first]); - requestlist_.push_back(fullatomlist_[neighbors_[i].second]); - } - Tools::removeDuplicates(requestlist_); - reduced=false; + requestlist_.clear(); + for(unsigned int i=0; i<size(); ++i) { + requestlist_.push_back(fullatomlist_[neighbors_[i].first]); + requestlist_.push_back(fullatomlist_[neighbors_[i].second]); + } + Tools::removeDuplicates(requestlist_); + reduced=false; } vector<AtomNumber>& NeighborList::getReducedAtomList() { - if(!reduced)for(unsigned int i=0;i<size();++i){ - unsigned newindex0=0,newindex1=0; - AtomNumber index0=fullatomlist_[neighbors_[i].first]; - AtomNumber index1=fullatomlist_[neighbors_[i].second]; + if(!reduced)for(unsigned int i=0; i<size(); ++i) { + unsigned newindex0=0,newindex1=0; + AtomNumber index0=fullatomlist_[neighbors_[i].first]; + AtomNumber index1=fullatomlist_[neighbors_[i].second]; // I exploit the fact that requestlist_ is an ordered vector - auto p = std::find(requestlist_.begin(), requestlist_.end(), index0); plumed_assert(p!=requestlist_.end()); newindex0=p-requestlist_.begin(); - p = std::find(requestlist_.begin(), requestlist_.end(), index1); plumed_assert(p!=requestlist_.end()); newindex1=p-requestlist_.begin(); - neighbors_[i]=pair<unsigned,unsigned>(newindex0,newindex1); - } - reduced=true; - return requestlist_; + auto p = std::find(requestlist_.begin(), requestlist_.end(), index0); plumed_assert(p!=requestlist_.end()); newindex0=p-requestlist_.begin(); + p = std::find(requestlist_.begin(), requestlist_.end(), index1); plumed_assert(p!=requestlist_.end()); newindex1=p-requestlist_.begin(); + neighbors_[i]=pair<unsigned,unsigned>(newindex0,newindex1); + } + reduced=true; + return requestlist_; } unsigned NeighborList::getStride() const { - return stride_; + return stride_; } unsigned NeighborList::getLastUpdate() const { - return lastupdate_; + return lastupdate_; } void NeighborList::setLastUpdate(unsigned step) { - lastupdate_=step; + lastupdate_=step; } unsigned NeighborList::size() const { - return neighbors_.size(); + return neighbors_.size(); } - pair<unsigned,unsigned> NeighborList::getClosePair(unsigned i) const { - return neighbors_[i]; +pair<unsigned,unsigned> NeighborList::getClosePair(unsigned i) const { + return neighbors_[i]; } vector<unsigned> NeighborList::getNeighbors(unsigned index) { - vector<unsigned> neighbors; - for(unsigned int i=0;i<size();++i){ - if(neighbors_[i].first==index) neighbors.push_back(neighbors_[i].second); - if(neighbors_[i].second==index) neighbors.push_back(neighbors_[i].first); - } - return neighbors; + vector<unsigned> neighbors; + for(unsigned int i=0; i<size(); ++i) { + if(neighbors_[i].first==index) neighbors.push_back(neighbors_[i].second); + if(neighbors_[i].second==index) neighbors.push_back(neighbors_[i].first); + } + return neighbors; } } diff --git a/src/tools/NeighborList.h b/src/tools/NeighborList.h index 61279d3d9..5afa87218 100644 --- a/src/tools/NeighborList.h +++ b/src/tools/NeighborList.h @@ -27,13 +27,13 @@ #include <vector> -namespace PLMD{ +namespace PLMD { class Pbc; /// \ingroup TOOLBOX /// A class that implements neighbor lists from two lists or a single list of atoms -class NeighborList +class NeighborList { bool reduced; bool do_pair_,do_pbc_,twolists_; @@ -45,30 +45,30 @@ class NeighborList /// Initialize the neighbor list with all possible pairs void initialize(); /// Return the pair of indexes in the positions array -/// of the two atoms forming the i-th pair among all possible pairs +/// of the two atoms forming the i-th pair among all possible pairs std::pair<unsigned,unsigned> getIndexPair(unsigned i); /// Extract the list of atoms from the current list of close pairs void setRequestList(); public: NeighborList(const std::vector<PLMD::AtomNumber>& list0, const std::vector<PLMD::AtomNumber>& list1, - const bool& do_pair, const bool& do_pbc, const PLMD::Pbc& pbc, + const bool& do_pair, const bool& do_pbc, const PLMD::Pbc& pbc, const double& distance=1.0e+30, const unsigned& stride=0); NeighborList(const std::vector<PLMD::AtomNumber>& list0, const bool& do_pbc, const PLMD::Pbc& pbc, const double& distance=1.0e+30, const unsigned& stride=0); -/// Return the list of all atoms. These are needed to rebuild the neighbor list. +/// Return the list of all atoms. These are needed to rebuild the neighbor list. std::vector<PLMD::AtomNumber>& getFullAtomList(); /// Update the indexes in the neighbor list to match the /// ordering in the new positions array /// and return the new list of atoms that must be requested to the main code std::vector<PLMD::AtomNumber>& getReducedAtomList(); /// Update the neighbor list and prepare the new -/// list of atoms that will be requested to the main code +/// list of atoms that will be requested to the main code void update(const std::vector<PLMD::Vector>& positions); /// Get the update stride of the neighbor list unsigned getStride() const; -/// Get the last step in which the neighbor list was updated +/// Get the last step in which the neighbor list was updated unsigned getLastUpdate() const; /// Set the step of the last update void setLastUpdate(unsigned step); @@ -78,7 +78,7 @@ public: std::pair<unsigned,unsigned> getClosePair(unsigned i) const; /// Get the list of neighbors of the i-th atom std::vector<unsigned> getNeighbors(unsigned i); - ~NeighborList(){} + ~NeighborList() {} }; } diff --git a/src/tools/OFile.cpp b/src/tools/OFile.cpp index dcadbd6ca..92108a132 100644 --- a/src/tools/OFile.cpp +++ b/src/tools/OFile.cpp @@ -38,14 +38,14 @@ #include <zlib.h> #endif -namespace PLMD{ +namespace PLMD { -size_t OFile::llwrite(const char*ptr,size_t s){ +size_t OFile::llwrite(const char*ptr,size_t s) { size_t r; if(linked) return linked->llwrite(ptr,s); - if(! (comm && comm->Get_rank()>0)){ + if(! (comm && comm->Get_rank()>0)) { if(!fp) plumed_merror("writing on uninitilized File"); - if(gzfp){ + if(gzfp) { #ifdef __PLUMED_HAS_ZLIB r=gzwrite(gzFile(gzfp),ptr,s); #else @@ -57,7 +57,7 @@ size_t OFile::llwrite(const char*ptr,size_t s){ } // This barrier is apparently useless since it comes // just before a Bcast. -// +// // Anyway, it looks like it is solving an issue that appeared on // TRAVIS (at least on my laptop) so I add it here. // GB @@ -80,40 +80,40 @@ OFile::OFile(): actual_buffer_length=0; buffer=new char[buflen]; // these are set to zero to avoid valgrind errors - for(unsigned i=0;i<buflen;++i) buffer[i]=0; + for(unsigned i=0; i<buflen; ++i) buffer[i]=0; buffer_string=new char [1000]; // these are set to zero to avoid valgrind errors - for(unsigned i=0;i<1000;++i) buffer_string[i]=0; + for(unsigned i=0; i<1000; ++i) buffer_string[i]=0; } -OFile::~OFile(){ +OFile::~OFile() { delete [] buffer_string; delete [] buffer; } -OFile& OFile::link(OFile&l){ +OFile& OFile::link(OFile&l) { fp=NULL; gzfp=NULL; linked=&l; return *this; } -OFile& OFile::setLinePrefix(const std::string&l){ +OFile& OFile::setLinePrefix(const std::string&l) { linePrefix=l; return *this; } -int OFile::printf(const char*fmt,...){ +int OFile::printf(const char*fmt,...) { va_list arg; va_start(arg, fmt); int r=std::vsnprintf(&buffer[actual_buffer_length],buflen-actual_buffer_length,fmt,arg); va_end(arg); - if(r>=buflen-actual_buffer_length){ + if(r>=buflen-actual_buffer_length) { int newlen=buflen; while(newlen<=r+actual_buffer_length) newlen*=2; char* newbuf=new char [newlen]; memmove(newbuf,buffer,buflen); - for(int k=buflen;k<newlen;k++) newbuf[k]=0; + for(int k=buflen; k<newlen; k++) newbuf[k]=0; delete [] buffer; buffer=newbuf; buflen=newlen; @@ -130,7 +130,7 @@ int OFile::printf(const char*fmt,...){ // newline is only searched in the just added portion: char*psearch=p1+actual_buffer_length; actual_buffer_length+=r; - while((p2=strchr(psearch,'\n'))){ + while((p2=strchr(psearch,'\n'))) { if(linePrefix.length()>0) llwrite(linePrefix.c_str(),linePrefix.length()); llwrite(p1,p2-p1+1); actual_buffer_length-=(p2-p1)+1; @@ -141,7 +141,7 @@ int OFile::printf(const char*fmt,...){ return r; } -OFile& OFile::addConstantField(const std::string&name){ +OFile& OFile::addConstantField(const std::string&name) { Field f; f.name=name; const_fields.push_back(f); @@ -149,39 +149,39 @@ OFile& OFile::addConstantField(const std::string&name){ } -OFile& OFile::clearFields(){ +OFile& OFile::clearFields() { fields.clear(); const_fields.clear(); previous_fields.clear(); return *this; } -OFile& OFile::fmtField(const std::string&fmt){ +OFile& OFile::fmtField(const std::string&fmt) { this->fieldFmt=fmt; return *this; } -OFile& OFile::fmtField(){ +OFile& OFile::fmtField() { this->fieldFmt="%23.16lg"; return *this; } -OFile& OFile::printField(const std::string&name,double v){ +OFile& OFile::printField(const std::string&name,double v) { sprintf(buffer_string,fieldFmt.c_str(),v); printField(name,buffer_string); return *this; } -OFile& OFile::printField(const std::string&name,int v){ +OFile& OFile::printField(const std::string&name,int v) { sprintf(buffer_string," %d",v); printField(name,buffer_string); return *this; } -OFile& OFile::printField(const std::string&name,const std::string & v){ +OFile& OFile::printField(const std::string&name,const std::string & v) { unsigned i; - for(i=0;i<const_fields.size();i++) if(const_fields[i].name==name) break; - if(i>=const_fields.size()){ + for(i=0; i<const_fields.size(); i++) if(const_fields[i].name==name) break; + if(i>=const_fields.size()) { Field field; field.name=name; field.value=v; @@ -193,45 +193,45 @@ OFile& OFile::printField(const std::string&name,const std::string & v){ return *this; } -OFile& OFile::setupPrintValue( Value *val ){ - if( val->isPeriodic() ){ - addConstantField("min_" + val->getName() ); - addConstantField("max_" + val->getName() ); +OFile& OFile::setupPrintValue( Value *val ) { + if( val->isPeriodic() ) { + addConstantField("min_" + val->getName() ); + addConstantField("max_" + val->getName() ); } return *this; } -OFile& OFile::printField( Value* val, const double& v ){ +OFile& OFile::printField( Value* val, const double& v ) { printField( val->getName(), v ); - if( val->isPeriodic() ){ - std::string min, max; val->getDomain( min, max ); - printField( "min_" + val->getName(), min ); - printField("max_" + val->getName(), max ); - } + if( val->isPeriodic() ) { + std::string min, max; val->getDomain( min, max ); + printField( "min_" + val->getName(), min ); + printField("max_" + val->getName(), max ); + } return *this; } -OFile& OFile::printField(){ +OFile& OFile::printField() { bool reprint=false; - if(fieldChanged || fields.size()!=previous_fields.size()){ + if(fieldChanged || fields.size()!=previous_fields.size()) { reprint=true; - } else for(unsigned i=0;i<fields.size();i++){ - if( previous_fields[i].name!=fields[i].name || - (fields[i].constant && fields[i].value!=previous_fields[i].value) ){ - reprint=true; - break; + } else for(unsigned i=0; i<fields.size(); i++) { + if( previous_fields[i].name!=fields[i].name || + (fields[i].constant && fields[i].value!=previous_fields[i].value) ) { + reprint=true; + break; + } } - } - if(reprint){ + if(reprint) { printf("#! FIELDS"); - for(unsigned i=0;i<fields.size();i++) printf(" %s",fields[i].name.c_str()); + for(unsigned i=0; i<fields.size(); i++) printf(" %s",fields[i].name.c_str()); printf("\n"); - for(unsigned i=0;i<const_fields.size();i++){ - printf("#! SET %s %s",const_fields[i].name.c_str(),const_fields[i].value.c_str()); - printf("\n"); + for(unsigned i=0; i<const_fields.size(); i++) { + printf("#! SET %s %s",const_fields[i].name.c_str(),const_fields[i].value.c_str()); + printf("\n"); } } - for(unsigned i=0;i<fields.size();i++) printf("%s",fields[i].value.c_str()); + for(unsigned i=0; i<fields.size(); i++) printf("%s",fields[i].value.c_str()); printf("\n"); previous_fields=fields; fields.clear(); @@ -239,11 +239,11 @@ OFile& OFile::printField(){ return *this; } -void OFile::setBackupString( const std::string& str ){ +void OFile::setBackupString( const std::string& str ) { backstring=str; } -void OFile::backupAllFiles( const std::string& str ){ +void OFile::backupAllFiles( const std::string& str ) { if(str=="/dev/null") return; plumed_assert( backstring!="bck" && !checkRestart()); size_t found=str.find_last_of("/\\"); @@ -251,42 +251,42 @@ void OFile::backupAllFiles( const std::string& str ){ std::string directory=filename.substr(0,found+1); std::string file=filename.substr(found+1); if( FileExist(filename) ) backupFile("bck", filename); - for(int i=0;;i++){ - std::string num; Tools::convert(i,num); - std::string filestr = directory + backstring + "." + num + "." + file; - if( !FileExist(filestr) ) break; - backupFile( "bck", filestr); + for(int i=0;; i++) { + std::string num; Tools::convert(i,num); + std::string filestr = directory + backstring + "." + num + "." + file; + if( !FileExist(filestr) ) break; + backupFile( "bck", filestr); } } -void OFile::backupFile( const std::string& bstring, const std::string& fname ){ - if(fname=="/dev/null") return; - int maxbackup=100; - if(std::getenv("PLUMED_MAXBACKUP")) Tools::convert(std::getenv("PLUMED_MAXBACKUP"),maxbackup); - if(maxbackup>0 && (!comm || comm->Get_rank()==0)){ - FILE* ff=std::fopen(const_cast<char*>(fname.c_str()),"r"); - if(ff){ - std::fclose(ff); - std::string backup; - size_t found=fname.find_last_of("/\\"); - std::string directory=fname.substr(0,found+1); - std::string file=fname.substr(found+1); - for(int i=0;;i++){ - std::string num; - Tools::convert(i,num); - if(i>maxbackup) plumed_merror("cannot backup file "+file+" maximum number of backup is "+num+"\n"); - backup=directory+bstring +"."+num+"."+file; - FILE* fff=std::fopen(backup.c_str(),"r"); - if(!fff) break; - else std::fclose(fff); - } - int check=rename(fname.c_str(),backup.c_str()); - plumed_massert(check==0,"renaming "+fname+" into "+backup+" failed for reason: "+strerror(errno)); - } - } +void OFile::backupFile( const std::string& bstring, const std::string& fname ) { + if(fname=="/dev/null") return; + int maxbackup=100; + if(std::getenv("PLUMED_MAXBACKUP")) Tools::convert(std::getenv("PLUMED_MAXBACKUP"),maxbackup); + if(maxbackup>0 && (!comm || comm->Get_rank()==0)) { + FILE* ff=std::fopen(const_cast<char*>(fname.c_str()),"r"); + if(ff) { + std::fclose(ff); + std::string backup; + size_t found=fname.find_last_of("/\\"); + std::string directory=fname.substr(0,found+1); + std::string file=fname.substr(found+1); + for(int i=0;; i++) { + std::string num; + Tools::convert(i,num); + if(i>maxbackup) plumed_merror("cannot backup file "+file+" maximum number of backup is "+num+"\n"); + backup=directory+bstring +"."+num+"."+file; + FILE* fff=std::fopen(backup.c_str(),"r"); + if(!fff) break; + else std::fclose(fff); + } + int check=rename(fname.c_str(),backup.c_str()); + plumed_massert(check==0,"renaming "+fname+" into "+backup+" failed for reason: "+strerror(errno)); + } + } } -OFile& OFile::open(const std::string&path){ +OFile& OFile::open(const std::string&path) { plumed_assert(!cloned); eof=false; err=false; @@ -294,26 +294,26 @@ OFile& OFile::open(const std::string&path){ gzfp=NULL; this->path=path; this->path=appendSuffix(path,getSuffix()); - if(checkRestart()){ - fp=std::fopen(const_cast<char*>(this->path.c_str()),"a"); - mode="a"; - if(Tools::extension(this->path)=="gz"){ + if(checkRestart()) { + fp=std::fopen(const_cast<char*>(this->path.c_str()),"a"); + mode="a"; + if(Tools::extension(this->path)=="gz") { #ifdef __PLUMED_HAS_ZLIB - gzfp=(void*)gzopen(const_cast<char*>(this->path.c_str()),"a9"); + gzfp=(void*)gzopen(const_cast<char*>(this->path.c_str()),"a9"); #else - plumed_merror("trying to use a gz file without zlib being linked"); + plumed_merror("trying to use a gz file without zlib being linked"); #endif - } + } } else { - backupFile( backstring, this->path ); - if(comm)comm->Barrier(); - fp=std::fopen(const_cast<char*>(this->path.c_str()),"w"); - mode="w"; - if(Tools::extension(this->path)=="gz"){ + backupFile( backstring, this->path ); + if(comm)comm->Barrier(); + fp=std::fopen(const_cast<char*>(this->path.c_str()),"w"); + mode="w"; + if(Tools::extension(this->path)=="gz") { #ifdef __PLUMED_HAS_ZLIB - gzfp=(void*)gzopen(const_cast<char*>(this->path.c_str()),"w9"); + gzfp=(void*)gzopen(const_cast<char*>(this->path.c_str()),"w9"); #else - plumed_merror("trying to use a gz file without zlib being linked"); + plumed_merror("trying to use a gz file without zlib being linked"); #endif } } @@ -321,18 +321,18 @@ OFile& OFile::open(const std::string&path){ return *this; } -OFile& OFile::rewind(){ +OFile& OFile::rewind() { // we use here "hard" rewind, which means close/reopen // the reason is that normal rewind does not work when in append mode // moreover, we can take a backup of the file plumed_assert(fp); clearFields(); - if(gzfp){ + if(gzfp) { #ifdef __PLUMED_HAS_ZLIB gzclose((gzFile)gzfp); #endif } else fclose(fp); - if(!comm || comm->Get_rank()==0){ + if(!comm || comm->Get_rank()==0) { std::string fname=this->path; size_t found=fname.find_last_of("/\\"); std::string directory=fname.substr(0,found+1); @@ -341,7 +341,7 @@ OFile& OFile::rewind(){ int check=rename(fname.c_str(),backup.c_str()); plumed_massert(check==0,"renaming "+fname+" into "+backup+" failed for reason: "+strerror(errno)); } - if(gzfp){ + if(gzfp) { #ifdef __PLUMED_HAS_ZLIB gzfp=(void*)gzopen(const_cast<char*>(this->path.c_str()),"w9"); #endif @@ -349,14 +349,14 @@ OFile& OFile::rewind(){ return *this; } -FileBase& OFile::flush(){ - if(heavyFlush){ - if(gzfp){ +FileBase& OFile::flush() { + if(heavyFlush) { + if(gzfp) { #ifdef __PLUMED_HAS_ZLIB gzclose(gzFile(gzfp)); gzfp=(void*)gzopen(const_cast<char*>(path.c_str()),"a"); #endif - } else{ + } else { fclose(fp); fp=std::fopen(const_cast<char*>(path.c_str()),"a"); } @@ -372,7 +372,7 @@ FileBase& OFile::flush(){ return *this; } -bool OFile::checkRestart()const{ +bool OFile::checkRestart()const { if(enforceRestart_) return true; else if(enforceBackup_) return false; else if(action) return action->getRestart(); @@ -380,13 +380,13 @@ bool OFile::checkRestart()const{ else return false; } -OFile& OFile::enforceRestart(){ +OFile& OFile::enforceRestart() { enforceRestart_=true; enforceBackup_=false; return *this; } -OFile& OFile::enforceBackup(){ +OFile& OFile::enforceBackup() { enforceBackup_=true; enforceRestart_=false; return *this; diff --git a/src/tools/OFile.h b/src/tools/OFile.h index 106d88b6b..84f044a94 100644 --- a/src/tools/OFile.h +++ b/src/tools/OFile.h @@ -26,7 +26,7 @@ #include <vector> #include <sstream> -namespace PLMD{ +namespace PLMD { class Value; @@ -90,7 +90,7 @@ the enforceRestart() method before opening a file. To have all files managed consistently, it is important to use OFile in the proper way. This should allow multi-replica plumed, restart and backups to work in -the expected way. For this reason all the operations in OFile and IFile +the expected way. For this reason all the operations in OFile and IFile are synchronizing all the processors of the group, so call to OFile functions should always be performed by all processes; for this reason is also not usefull to use Log for debugging because only master threads will actually write. @@ -129,7 +129,7 @@ int main(){ snp.flush(); // the only difference is that snp is rewound // notice that it should be rewound just before writing -// because rewind is going to move the file out of the way +// because rewind is going to move the file out of the way // to have a safe copy of the file ("bck.last.filename") // Also notice that snapshots should be flushed // for this reason, it is better to write them only @@ -145,7 +145,7 @@ int main(){ */ class OFile: -public virtual FileBase{ + public virtual FileBase { /// Pointer to a linked OFile. /// see link(OFile&) OFile* linked; @@ -159,7 +159,7 @@ public virtual FileBase{ unsigned actual_buffer_length; /// Class identifying a single field for fielded output class Field: - public FieldBase{ + public FieldBase { }; /// Low-level write size_t llwrite(const char*,size_t); @@ -208,13 +208,13 @@ public: /// Backup a file by giving it a different name void backupFile( const std::string& bstring, const std::string& fname ); /// This backs up all the files that would have been created with the -/// name str. It is used in analysis when you are not restarting. Analysis +/// name str. It is used in analysis when you are not restarting. Analysis /// output files at different times, which are names analysis.0.<filename>, /// analysis.1.<filename> and <filename>, are backed up to bck.0.analysis.0.<filename>, /// bck.0.analysis.1.<filename> and bck.0.<filename> void backupAllFiles( const std::string& str ); /// Opens the file using automatic append/backup - OFile& open(const std::string&name); + OFile& open(const std::string&name); /// Set the prefix for output. /// Typically "PLUMED: ". Notice that lines with a prefix cannot /// be parsed using fields in a IFile. @@ -235,18 +235,18 @@ public: OFile& setupPrintValue( Value *val ); /// Print a value OFile& printField( Value* val, const double& v ); -/** Close a line. -Typically used as -\verbatim - of.printField("a",a).printField("b",b).printField(); -\endverbatim -*/ + /** Close a line. + Typically used as + \verbatim + of.printField("a",a).printField("b",b).printField(); + \endverbatim + */ OFile& printField(); -/** -Resets the list of fields. -As it is only possible to add new constant fields (addConstantField()), -this method can be used to clean the field list. -*/ + /** + Resets the list of fields. + As it is only possible to add new constant fields (addConstantField()), + this method can be used to clean the field list. + */ OFile& clearFields(); /// Formatted output with explicit format - a la printf int printf(const char*fmt,...); @@ -266,7 +266,7 @@ this method can be used to clean the field list. /// Write using << syntax template <class T> -OFile& operator<<(OFile&of,const T &t){ +OFile& operator<<(OFile&of,const T &t) { of.oss<<t; of.printf("%s",of.oss.str().c_str()); of.oss.str(""); diff --git a/src/tools/OpenMP.cpp b/src/tools/OpenMP.cpp index 3a5d24936..928c3da15 100644 --- a/src/tools/OpenMP.cpp +++ b/src/tools/OpenMP.cpp @@ -24,15 +24,15 @@ #include "Tools.h" #include <cstdlib> -namespace PLMD{ +namespace PLMD { -unsigned OpenMP::getCachelineSize(){ +unsigned OpenMP::getCachelineSize() { static unsigned cachelineSize=512; if(std::getenv("PLUMED_CACHELINE_SIZE")) Tools::convert(std::getenv("PLUMED_CACHELINE_SIZE"),cachelineSize); return cachelineSize; } -unsigned OpenMP::getNumThreads(){ +unsigned OpenMP::getNumThreads() { static unsigned numThreads=1; if(std::getenv("PLUMED_NUM_THREADS")) Tools::convert(std::getenv("PLUMED_NUM_THREADS"),numThreads); return numThreads; diff --git a/src/tools/OpenMP.h b/src/tools/OpenMP.h index 418451c17..c79258ff7 100644 --- a/src/tools/OpenMP.h +++ b/src/tools/OpenMP.h @@ -24,30 +24,30 @@ #include <vector> -namespace PLMD{ +namespace PLMD { -class OpenMP{ +class OpenMP { public: /// Get number of threads that can be used by openMP -static unsigned getNumThreads(); + static unsigned getNumThreads(); /// get cacheline size -static unsigned getCachelineSize(); + static unsigned getCachelineSize(); /// Get a reasonable number of threads so as to access to an array of size s located at x -template<typename T> -static unsigned getGoodNumThreads(const T*x,unsigned s); + template<typename T> + static unsigned getGoodNumThreads(const T*x,unsigned s); /// Get a reasonable number of threads so as to access to vector v; -template<typename T> -static unsigned getGoodNumThreads(const std::vector<T> & v); + template<typename T> + static unsigned getGoodNumThreads(const std::vector<T> & v); }; template<typename T> -unsigned OpenMP::getGoodNumThreads(const T*x,unsigned n){ +unsigned OpenMP::getGoodNumThreads(const T*x,unsigned n) { unsigned long p=(unsigned long) x; (void) p; // this is not to have warnings. notice that the pointer location is not used actually. // a factor two is necessary since there is no guarantee that x is aligned @@ -61,7 +61,7 @@ unsigned OpenMP::getGoodNumThreads(const T*x,unsigned n){ template<typename T> -unsigned OpenMP::getGoodNumThreads(const std::vector<T> & v){ +unsigned OpenMP::getGoodNumThreads(const std::vector<T> & v) { if(v.size()==0) return 1; else return getGoodNumThreads(&v[0],v.size()); } diff --git a/src/tools/PDB.cpp b/src/tools/PDB.cpp index f4e0d398a..128e4620e 100644 --- a/src/tools/PDB.cpp +++ b/src/tools/PDB.cpp @@ -27,14 +27,14 @@ using namespace std; -namespace PLMD{ +namespace PLMD { /// Tiny namespace for hybrid36 format. /// This namespace includes freely available tools for h36 format. /// I place them here for usage within PDB class. In case we need them /// in other places they might be better encapsulated in a c++ class /// and placed in a separate file. -namespace h36{ +namespace h36 { /*! C port of the hy36encode() and hy36decode() functions in the @@ -117,7 +117,7 @@ encode_pure( value = rest; } if (j) buf[i++] = '-'; - for(j=i;j<width;j++) *result++ = ' '; + for(j=i; j<width; j++) *result++ = ' '; while (i != 0) *result++ = buf[--i]; *result = '\0'; } @@ -136,7 +136,7 @@ decode_pure( int have_non_blank = 0; int value = 0; unsigned i = 0; - for(;i<s_size;i++) { + for(; i<s_size; i++) { si = s[i]; if (si < 0 || si > 127) { *result = 0; @@ -270,15 +270,15 @@ hy36decode(unsigned width, const char* s, unsigned s_size, int* result) static int digits_values_upper[128U]; static int digits_values_lower[128U]; static const char* - ie_range = "internal error hy36decode: integer value out of range."; + ie_range = "internal error hy36decode: integer value out of range."; unsigned i; int di; const char* errmsg; if (first_call) { first_call = 0; - for(i=0;i<128U;i++) digits_values_upper[i] = -1; - for(i=0;i<128U;i++) digits_values_lower[i] = -1; - for(i=0;i<36U;i++) { + for(i=0; i<128U; i++) digits_values_upper[i] = -1; + for(i=0; i<128U; i++) digits_values_lower[i] = -1; + for(i=0; i<36U; i++) { di = digits_upper()[i]; if (di < 0 || di > 127) { *result = 0; @@ -286,7 +286,7 @@ hy36decode(unsigned width, const char* s, unsigned s_size, int* result) } digits_values_upper[di] = i; } - for(i=0;i<36U;i++) { + for(i=0; i<36U; i++) { di = digits_lower()[i]; if (di < 0 || di > 127) { *result = 0; @@ -341,72 +341,72 @@ hy36decode(unsigned width, const char* s, unsigned s_size, int* result) } -unsigned PDB::getNumberOfAtomBlocks()const{ +unsigned PDB::getNumberOfAtomBlocks()const { return block_ends.size(); } -const std::vector<unsigned> & PDB::getAtomBlockEnds()const{ +const std::vector<unsigned> & PDB::getAtomBlockEnds()const { return block_ends; } -const std::vector<Vector> & PDB::getPositions()const{ +const std::vector<Vector> & PDB::getPositions()const { return positions; } -void PDB::setPositions(const std::vector<Vector> &v ){ - plumed_assert( v.size()==positions.size() ); - positions=v; +void PDB::setPositions(const std::vector<Vector> &v ) { + plumed_assert( v.size()==positions.size() ); + positions=v; } -const std::vector<double> & PDB::getOccupancy()const{ +const std::vector<double> & PDB::getOccupancy()const { return occupancy; } -const std::vector<double> & PDB::getBeta()const{ +const std::vector<double> & PDB::getBeta()const { return beta; } -const std::vector<std::string> & PDB::getRemark()const{ +const std::vector<std::string> & PDB::getRemark()const { return remark; } -void PDB::addRemark( const std::vector<std::string>& v1 ){ +void PDB::addRemark( const std::vector<std::string>& v1 ) { remark.insert(remark.begin(),v1.begin(),v1.end()); } -const std::vector<AtomNumber> & PDB::getAtomNumbers()const{ +const std::vector<AtomNumber> & PDB::getAtomNumbers()const { return numbers; } -std::string PDB::getAtomName(AtomNumber a)const{ +std::string PDB::getAtomName(AtomNumber a)const { const auto p=number2index.find(a); if(p==number2index.end()) return ""; else return atomsymb[p->second]; } -unsigned PDB::getResidueNumber(AtomNumber a)const{ +unsigned PDB::getResidueNumber(AtomNumber a)const { const auto p=number2index.find(a); if(p==number2index.end()) return 0; else return residue[p->second]; } -std::string PDB::getResidueName(AtomNumber a) const{ +std::string PDB::getResidueName(AtomNumber a) const { const auto p=number2index.find(a); if(p==number2index.end()) return ""; else return residuenames[p->second]; } -unsigned PDB::size()const{ +unsigned PDB::size()const { return positions.size(); } -bool PDB::readFromFilepointer(FILE *fp,bool naturalUnits,double scale){ +bool PDB::readFromFilepointer(FILE *fp,bool naturalUnits,double scale) { //cerr<<file<<endl; bool file_is_alive=false; if(naturalUnits) scale=1.0; string line; fpos_t pos; bool between_ters=true; - while(Tools::getline(fp,line)){ + while(Tools::getline(fp,line)) { //cerr<<line<<"\n"; fgetpos (fp,&pos); while(line.length()<80) line.push_back(' '); @@ -422,14 +422,14 @@ bool PDB::readFromFilepointer(FILE *fp,bool naturalUnits,double scale){ string occ=line.substr(54,6); string bet=line.substr(60,6); Tools::trim(record); - if(record=="TER"){ between_ters=false; block_ends.push_back( positions.size() ); } - if(record=="END"){ file_is_alive=true; break;} - if(record=="ENDMDL"){ file_is_alive=true; break;} - if(record=="REMARK"){ - vector<string> v1; v1=Tools::getWords(line.substr(6)); - addRemark( v1 ); + if(record=="TER") { between_ters=false; block_ends.push_back( positions.size() ); } + if(record=="END") { file_is_alive=true; break;} + if(record=="ENDMDL") { file_is_alive=true; break;} + if(record=="REMARK") { + vector<string> v1; v1=Tools::getWords(line.substr(6)); + addRemark( v1 ); } - if(record=="ATOM" || record=="HETATM"){ + if(record=="ATOM" || record=="HETATM") { between_ters=true; AtomNumber a; unsigned resno; double o,b; @@ -439,7 +439,7 @@ bool PDB::readFromFilepointer(FILE *fp,bool naturalUnits,double scale){ { int result; const char* errmsg = h36::hy36decode(5, serial.c_str(),5, &result); - if(errmsg){ + if(errmsg) { std::string msg(errmsg); plumed_merror(msg); } @@ -471,17 +471,17 @@ bool PDB::readFromFilepointer(FILE *fp,bool naturalUnits,double scale){ return file_is_alive; } -void PDB::setArgKeyword( const std::string& new_args ){ +void PDB::setArgKeyword( const std::string& new_args ) { bool replaced=false; - for(unsigned i=0;i<remark.size();++i){ - if( remark[i].find("ARG=")!=std::string::npos){ - remark[i]=new_args; replaced=true; - } + for(unsigned i=0; i<remark.size(); ++i) { + if( remark[i].find("ARG=")!=std::string::npos) { + remark[i]=new_args; replaced=true; + } } plumed_assert( replaced ); } -bool PDB::read(const std::string&file,bool naturalUnits,double scale){ +bool PDB::read(const std::string&file,bool naturalUnits,double scale) { FILE* fp=fopen(file.c_str(),"r"); if(!fp) return false; readFromFilepointer(fp,naturalUnits,scale); @@ -492,72 +492,72 @@ bool PDB::read(const std::string&file,bool naturalUnits,double scale){ void PDB::getChainNames( std::vector<std::string>& chains ) const { chains.resize(0); chains.push_back( chain[0] ); - for(unsigned i=1;i<size();++i){ - if( chains[chains.size()-1]!=chain[i] ) chains.push_back( chain[i] ); + for(unsigned i=1; i<size(); ++i) { + if( chains[chains.size()-1]!=chain[i] ) chains.push_back( chain[i] ); } -} +} void PDB::getResidueRange( const std::string& chainname, unsigned& res_start, unsigned& res_end, std::string& errmsg ) const { bool inres=false, foundchain=false; - for(unsigned i=0;i<size();++i){ - if( chain[i]==chainname ){ - if(!inres){ - if(foundchain) errmsg="found second start of chain named " + chainname; - res_start=residue[i]; - } - inres=true; foundchain=true; - } else if( inres && chain[i]!=chainname ){ - inres=false; - res_end=residue[i-1]; - } + for(unsigned i=0; i<size(); ++i) { + if( chain[i]==chainname ) { + if(!inres) { + if(foundchain) errmsg="found second start of chain named " + chainname; + res_start=residue[i]; + } + inres=true; foundchain=true; + } else if( inres && chain[i]!=chainname ) { + inres=false; + res_end=residue[i-1]; + } } if(inres) res_end=residue[size()-1]; } void PDB::getAtomRange( const std::string& chainname, AtomNumber& a_start, AtomNumber& a_end, std::string& errmsg ) const { bool inres=false, foundchain=false; - for(unsigned i=0;i<size();++i){ - if( chain[i]==chainname ){ - if(!inres){ - if(foundchain) errmsg="found second start of chain named " + chainname; - a_start=numbers[i]; - } - inres=true; foundchain=true; - } else if( inres && chain[i]!=chainname ){ - inres=false; - a_end=numbers[i-1]; - } - } + for(unsigned i=0; i<size(); ++i) { + if( chain[i]==chainname ) { + if(!inres) { + if(foundchain) errmsg="found second start of chain named " + chainname; + a_start=numbers[i]; + } + inres=true; foundchain=true; + } else if( inres && chain[i]!=chainname ) { + inres=false; + a_end=numbers[i-1]; + } + } if(inres) a_end=numbers[size()-1]; -} +} std::string PDB::getResidueName( const unsigned& resnum ) const { - for(unsigned i=0;i<size();++i){ - if( residue[i]==resnum ) return residuenames[i]; + for(unsigned i=0; i<size(); ++i) { + if( residue[i]==resnum ) return residuenames[i]; } return ""; } std::string PDB::getResidueName(const unsigned& resnum,const std::string& chainid ) const { - for(unsigned i=0;i<size();++i){ - if( residue[i]==resnum && ( chainid=="*" || chain[i]==chainid) ) return residuenames[i]; + for(unsigned i=0; i<size(); ++i) { + if( residue[i]==resnum && ( chainid=="*" || chain[i]==chainid) ) return residuenames[i]; } return ""; } AtomNumber PDB::getNamedAtomFromResidue( const std::string& aname, const unsigned& resnum ) const { - for(unsigned i=0;i<size();++i){ - if( residue[i]==resnum && atomsymb[i]==aname ) return numbers[i]; + for(unsigned i=0; i<size(); ++i) { + if( residue[i]==resnum && atomsymb[i]==aname ) return numbers[i]; } std::string num; Tools::convert( resnum, num ); plumed_merror("residue " + num + " does not contain an atom named " + aname ); return numbers[0]; // This is to stop compiler errors } -AtomNumber PDB::getNamedAtomFromResidueAndChain( const std::string& aname, const unsigned& resnum, const std::string& chainid ) const{ - for(unsigned i=0;i<size();++i){ - if( residue[i]==resnum && atomsymb[i]==aname && ( chainid=="*" || chain[i]==chainid) ) return numbers[i]; +AtomNumber PDB::getNamedAtomFromResidueAndChain( const std::string& aname, const unsigned& resnum, const std::string& chainid ) const { + for(unsigned i=0; i<size(); ++i) { + if( residue[i]==resnum && atomsymb[i]==aname && ( chainid=="*" || chain[i]==chainid) ) return numbers[i]; } std::string num; Tools::convert( resnum, num ); plumed_merror("residue " + num + " from chain " + chainid + " does not contain an atom named " + aname ); @@ -566,8 +566,8 @@ AtomNumber PDB::getNamedAtomFromResidueAndChain( const std::string& aname, const std::vector<AtomNumber> PDB::getAtomsInResidue(const unsigned& resnum,const std::string& chainid)const { std::vector<AtomNumber> tmp; - for(unsigned i=0;i<size();++i){ - if( residue[i]==resnum && ( chainid=="*" || chain[i]==chainid) ) tmp.push_back(numbers[i]); + for(unsigned i=0; i<size(); ++i) { + if( residue[i]==resnum && ( chainid=="*" || chain[i]==chainid) ) tmp.push_back(numbers[i]); } if(tmp.size()==0) { std::string num; Tools::convert( resnum, num ); @@ -578,8 +578,8 @@ std::vector<AtomNumber> PDB::getAtomsInResidue(const unsigned& resnum,const std: std::vector<AtomNumber> PDB::getAtomsInChain(const std::string& chainid)const { std::vector<AtomNumber> tmp; - for(unsigned i=0;i<size();++i){ - if( chainid=="*" || chain[i]==chainid ) tmp.push_back(numbers[i]); + for(unsigned i=0; i<size(); ++i) { + if( chainid=="*" || chain[i]==chainid ) tmp.push_back(numbers[i]); } if(tmp.size()==0) { plumed_merror("Cannot find atoms from chain " + chainid ); @@ -588,39 +588,39 @@ std::vector<AtomNumber> PDB::getAtomsInChain(const std::string& chainid)const { } std::string PDB::getChainID(const unsigned& resnumber) const { - for(unsigned i=0;i<size();++i){ - if(resnumber==residue[i]) return chain[i]; + for(unsigned i=0; i<size(); ++i) { + if(resnumber==residue[i]) return chain[i]; } plumed_merror("Not enough residues in pdb input file"); } bool PDB::checkForResidue( const std::string& name ) const { - for(unsigned i=0;i<size();++i){ - if( residuenames[i]==name ) return true; + for(unsigned i=0; i<size(); ++i) { + if( residuenames[i]==name ) return true; } return false; } bool PDB::checkForAtom( const std::string& name ) const { - for(unsigned i=0;i<size();++i){ - if( atomsymb[i]==name ) return true; + for(unsigned i=0; i<size(); ++i) { + if( atomsymb[i]==name ) return true; } return false; } -Log& operator<<(Log& ostr, const PDB& pdb){ - char buffer[1000]; - for(unsigned i=0;i<pdb.positions.size();i++){ - sprintf(buffer,"ATOM %3d %8.3f %8.3f %8.3f\n",pdb.numbers[i].serial(),pdb.positions[i][0],pdb.positions[i][1],pdb.positions[i][2]); - ostr<<buffer; - } - return ostr; +Log& operator<<(Log& ostr, const PDB& pdb) { + char buffer[1000]; + for(unsigned i=0; i<pdb.positions.size(); i++) { + sprintf(buffer,"ATOM %3d %8.3f %8.3f %8.3f\n",pdb.numbers[i].serial(),pdb.positions[i][0],pdb.positions[i][1],pdb.positions[i][2]); + ostr<<buffer; + } + return ostr; } -Vector PDB::getPosition(AtomNumber a)const{ - const auto p=number2index.find(a); - if(p==number2index.end()) plumed_merror("atom not available"); - else return positions[p->second]; +Vector PDB::getPosition(AtomNumber a)const { + const auto p=number2index.find(a); + if(p==number2index.end()) plumed_merror("atom not available"); + else return positions[p->second]; } diff --git a/src/tools/PDB.h b/src/tools/PDB.h index 059ea4f6c..05cee0a8a 100644 --- a/src/tools/PDB.h +++ b/src/tools/PDB.h @@ -29,14 +29,14 @@ #include <map> -namespace PLMD{ +namespace PLMD { class Log; /// Minimalistic pdb parser. /// Contain positions, atomic indexes, occupancy and beta. /// We should also add other info (e.g. residue name etc). -class PDB{ +class PDB { std::vector<unsigned> block_ends; std::vector<std::string> atomsymb, chain; std::vector<unsigned> residue; @@ -59,11 +59,11 @@ public: /// Access to the beta array const std::vector<double> & getBeta()const; /// This is used to set the keyword ARG - this is so we -/// we can use a1.* in the input for reference configurations +/// we can use a1.* in the input for reference configurations void setArgKeyword( const std::string& new_args ); /// Add information to the remark void addRemark( const std::vector<std::string>& v1 ); -/// Access to the lines of REMARK +/// Access to the lines of REMARK const std::vector<std::string> & getRemark()const; /// Access to the indexes const std::vector<AtomNumber> & getAtomNumbers()const; @@ -73,11 +73,11 @@ public: void getChainNames( std::vector<std::string>& chains ) const; /// Get the residues in each of the chains void getResidueRange( const std::string& chainname, unsigned& res_start, unsigned& res_end, std::string& errmsg ) const; -/// Get the atoms in each of the chains +/// Get the atoms in each of the chains void getAtomRange( const std::string& chainname, AtomNumber& a_start, AtomNumber& a_end, std::string& errmsg ) const; /// Get the chain ID that a particular residue is a part of std::string getChainID(const unsigned& resnumber) const; -///use the log to dump information +///use the log to dump information friend Log& operator<<(Log& ostr, const PDB& pdb); /// return the name of a specific atom std::string getAtomName(AtomNumber a) const; @@ -99,9 +99,9 @@ public: /// Return the atom named aname from residue number resnum and chain. /// Chain=="*" matches any chain and makes it equivalent to getNamedAtomFromResidue. AtomNumber getNamedAtomFromResidueAndChain( const std::string& aname, const unsigned& resnum, const std::string& chain ) const; -/// Access to the atoms of a residue +/// Access to the atoms of a residue std::vector<AtomNumber> getAtomsInResidue(const unsigned& resnum,const std::string& chainid)const; -/// Access to the atoms of a chain +/// Access to the atoms of a chain std::vector<AtomNumber> getAtomsInChain(const std::string& chainid)const; /// Get the extents of the blocks containing the atoms const std::vector<unsigned> & getAtomBlockEnds() const ; diff --git a/src/tools/Pbc.cpp b/src/tools/Pbc.cpp index 025a2fa44..ff0ac18b0 100644 --- a/src/tools/Pbc.cpp +++ b/src/tools/Pbc.cpp @@ -27,7 +27,7 @@ #include "Random.h" #include <cmath> -namespace PLMD{ +namespace PLMD { Pbc::Pbc(): type(unset) @@ -36,83 +36,83 @@ Pbc::Pbc(): invBox.zero(); } -void Pbc::buildShifts(std::vector<Vector> shifts[2][2][2])const{ +void Pbc::buildShifts(std::vector<Vector> shifts[2][2][2])const { const double small=1e-28; // clear all shifts - for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) shifts[i][j][k].clear(); + for(int i=0; i<2; i++) for(int j=0; j<2; j++) for(int k=0; k<2; k++) shifts[i][j][k].clear(); // enumerate all possible shifts // since box is reduced, only 27 shifts have to be attempted - for(int l=-1;l<=1;l++) for(int m=-1;m<=1;m++) for(int n=-1;n<=1;n++){ + for(int l=-1; l<=1; l++) for(int m=-1; m<=1; m++) for(int n=-1; n<=1; n++) { // int/double shift vectors - int ishift[3]={l,m,n}; - Vector dshift(l,m,n); + int ishift[3]= {l,m,n}; + Vector dshift(l,m,n); // count how many components are != 0 - unsigned count=0; - for(int s=0;s<3;s++) if(ishift[s]!=0) count++; + unsigned count=0; + for(int s=0; s<3; s++) if(ishift[s]!=0) count++; // skips trivial (0,0,0) and cases with three shifts // only 18 shifts survive past this point - if(count==0 || count==3) continue; + if(count==0 || count==3) continue; // check if that Wigner-Seitz face is perpendicular to the axis. // this allows to eliminate shifts in symmetric cells. // e.g., if one lactice vector is orthogonal to the plane spanned // by the other two vectors, that shift should never be tried - Vector cosdir=matmul(reduced,transpose(reduced),dshift); - double dp=dotProduct(dshift,cosdir); - double ref=modulo2(dshift)*modulo2(cosdir); - if(std::fabs(ref-dp*dp)<small) continue; + Vector cosdir=matmul(reduced,transpose(reduced),dshift); + double dp=dotProduct(dshift,cosdir); + double ref=modulo2(dshift)*modulo2(cosdir); + if(std::fabs(ref-dp*dp)<small) continue; // here we start pruning depending on the sign of the scaled coordinate - for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++){ + for(int i=0; i<2; i++) for(int j=0; j<2; j++) for(int k=0; k<2; k++) { - int block[3]={2*i-1,2*j-1,2*k-1}; + int block[3]= {2*i-1,2*j-1,2*k-1}; // skip cases where shift would bring too far from origin - bool skip=false; - for(int s=0;s<3;s++) if(ishift[s]*block[s]>0) skip=true; - if(skip) continue; - skip=true; - for(int s=0;s<3;s++){ + bool skip=false; + for(int s=0; s<3; s++) if(ishift[s]*block[s]>0) skip=true; + if(skip) continue; + skip=true; + for(int s=0; s<3; s++) { // check that the components of cosdir along the non-shifted directions // have the proper sign - if(((1-ishift[s]*ishift[s])*block[s])*cosdir[s]<-small) skip=false; - } - if(skip)continue; + if(((1-ishift[s]*ishift[s])*block[s])*cosdir[s]<-small) skip=false; + } + if(skip)continue; // if we arrive to this point, shift is eligible and is added to the list - shifts[i][j][k].push_back(matmul(transpose(reduced),dshift)); - } - } + shifts[i][j][k].push_back(matmul(transpose(reduced),dshift)); + } + } } -void Pbc::fullSearch(Vector&d)const{ - if(type==unset) return; - Vector s=matmul(invReduced.transpose(),d); - for(int i=0;i<3;i++) s[i]=Tools::pbc(s[i]); - d=matmul(reduced.transpose(),s); - const int smax=4; - Vector a0(reduced.getRow(0)); - Vector a1(reduced.getRow(1)); - Vector a2(reduced.getRow(2)); - Vector best(d); - double lbest=d.modulo2(); - for(int i=-smax;i<=smax;i++) for(int j=-smax;j<=smax;j++) for(int k=-smax;k<=smax;k++){ - Vector trial=d+i*a0+j*a1+k*a2; - double ltrial=trial.modulo2(); - if(ltrial<lbest){ - best=trial; - lbest=ltrial; - } - } - d=best; +void Pbc::fullSearch(Vector&d)const { + if(type==unset) return; + Vector s=matmul(invReduced.transpose(),d); + for(int i=0; i<3; i++) s[i]=Tools::pbc(s[i]); + d=matmul(reduced.transpose(),s); + const int smax=4; + Vector a0(reduced.getRow(0)); + Vector a1(reduced.getRow(1)); + Vector a2(reduced.getRow(2)); + Vector best(d); + double lbest=d.modulo2(); + for(int i=-smax; i<=smax; i++) for(int j=-smax; j<=smax; j++) for(int k=-smax; k<=smax; k++) { + Vector trial=d+i*a0+j*a1+k*a2; + double ltrial=trial.modulo2(); + if(ltrial<lbest) { + best=trial; + lbest=ltrial; + } + } + d=best; } -void Pbc::setBox(const Tensor&b){ +void Pbc::setBox(const Tensor&b) { box=b; // detect type: const double epsilon=1e-28; @@ -133,60 +133,60 @@ void Pbc::setBox(const Tensor&b){ if(cxy && cxz && cyz) type=orthorombic; else type=generic; - if(type==orthorombic){ - reduced=box; - invReduced=inverse(reduced); - for(unsigned i=0;i<3;i++){ + if(type==orthorombic) { + reduced=box; + invReduced=inverse(reduced); + for(unsigned i=0; i<3; i++) { diag[i]=box[i][i]; hdiag[i]=0.5*box[i][i]; mdiag[i]=-0.5*box[i][i]; } - } else { - reduced=box; - LatticeReduction::reduce(reduced); - invReduced=inverse(reduced); - buildShifts(shifts); -} + } else { + reduced=box; + LatticeReduction::reduce(reduced); + invReduced=inverse(reduced); + buildShifts(shifts); + } } double Pbc::distance( const bool pbc, const Vector& v1, const Vector& v2 ) const { - if(pbc){ return ( distance(v1,v2) ).modulo(); } - else{ return ( delta(v1,v2) ).modulo(); } + if(pbc) { return ( distance(v1,v2) ).modulo(); } + else { return ( delta(v1,v2) ).modulo(); } } void Pbc::apply(std::vector<Vector>& dlist, unsigned max_index) const { - if (max_index==0) max_index=dlist.size(); - if(type==unset){ + if (max_index==0) max_index=dlist.size(); + if(type==unset) { } else if(type==orthorombic) { #ifdef __PLUMED_PBC_WHILE - for(unsigned k=0;k<max_index;++k){ + for(unsigned k=0; k<max_index; ++k) { while(dlist[k][0]>hdiag[0]) dlist[k][0]-=diag[0]; while(dlist[k][0]<=mdiag[0]) dlist[k][0]+=diag[0]; while(dlist[k][1]>hdiag[1]) dlist[k][1]-=diag[1]; while(dlist[k][1]<=mdiag[1]) dlist[k][1]+=diag[1]; while(dlist[k][2]>hdiag[2]) dlist[k][2]-=diag[2]; - while(dlist[k][2]<=mdiag[2]) dlist[k][2]+=diag[2]; - } + while(dlist[k][2]<=mdiag[2]) dlist[k][2]+=diag[2]; + } #else - for(unsigned k=0;k<max_index;++k) for(int i=0;i<3;i++) dlist[k][i]=Tools::pbc(dlist[k][i]*invBox(i,i))*box(i,i); + for(unsigned k=0; k<max_index; ++k) for(int i=0; i<3; i++) dlist[k][i]=Tools::pbc(dlist[k][i]*invBox(i,i))*box(i,i); #endif } else if(type==generic) { - for(unsigned k=0;k<max_index;++k) dlist[k]=distance(Vector(0.0,0.0,0.0),dlist[k]); + for(unsigned k=0; k<max_index; ++k) dlist[k]=distance(Vector(0.0,0.0,0.0),dlist[k]); } else plumed_merror("unknown pbc type"); } -Vector Pbc::distance(const Vector&v1,const Vector&v2,int*nshifts)const{ +Vector Pbc::distance(const Vector&v1,const Vector&v2,int*nshifts)const { Vector d=delta(v1,v2); - if(type==unset){ + if(type==unset) { } else if(type==orthorombic) { #ifdef __PLUMED_PBC_WHILE - for(unsigned i=0;i<3;i++){ + for(unsigned i=0; i<3; i++) { while(d[i]>hdiag[i]) d[i]-=diag[i]; while(d[i]<=mdiag[i]) d[i]+=diag[i]; } #else - for(int i=0;i<3;i++) d[i]=Tools::pbc(d[i]*invBox(i,i))*box(i,i); + for(int i=0; i<3; i++) d[i]=Tools::pbc(d[i]*invBox(i,i))*box(i,i); #endif } else if(type==generic) { Vector s=matmul(d,invReduced); @@ -195,22 +195,22 @@ Vector Pbc::distance(const Vector&v1,const Vector&v2,int*nshifts)const{ // NOTICE: the check in the previous line, albeit correct, is breaking many regtest // since it does not apply Tools::pbc in many cases. Moreover, it does not // introduce a significant gain. I thus leave it out for the moment. - if(true){ + if(true) { // bring to -0.5,+0.5 region in scaled coordinates: - for(int i=0;i<3;i++) s[i]=Tools::pbc(s[i]); + for(int i=0; i<3; i++) s[i]=Tools::pbc(s[i]); d=matmul(s,reduced); // check if shifts have to be attempted: - if((std::fabs(s[0])+std::fabs(s[1])+std::fabs(s[2])>0.5)){ + if((std::fabs(s[0])+std::fabs(s[1])+std::fabs(s[2])>0.5)) { // list of shifts is specific for that "octant" (depends on signs of s[i]): const std::vector<Vector> & myshifts(shifts[(s[0]>0?1:0)][(s[1]>0?1:0)][(s[2]>0?1:0)]); Vector best(d); double lbest(modulo2(best)); // loop over possible shifts: if(nshifts) *nshifts+=myshifts.size(); - for(unsigned i=0;i<myshifts.size();i++){ + for(unsigned i=0; i<myshifts.size(); i++) { Vector trial=d+myshifts[i]; double ltrial=modulo2(trial); - if(ltrial<lbest){ + if(ltrial<lbest) { lbest=ltrial; best=trial; } @@ -222,23 +222,23 @@ Vector Pbc::distance(const Vector&v1,const Vector&v2,int*nshifts)const{ return d; } -Vector Pbc::realToScaled(const Vector&d)const{ +Vector Pbc::realToScaled(const Vector&d)const { return matmul(invBox.transpose(),d); } -Vector Pbc::scaledToReal(const Vector&d)const{ +Vector Pbc::scaledToReal(const Vector&d)const { return matmul(box.transpose(),d); } -bool Pbc::isOrthorombic()const{ +bool Pbc::isOrthorombic()const { return type==orthorombic; } -const Tensor& Pbc::getBox()const{ +const Tensor& Pbc::getBox()const { return box; } -const Tensor& Pbc::getInvBox()const{ +const Tensor& Pbc::getInvBox()const { return invBox; } diff --git a/src/tools/Pbc.h b/src/tools/Pbc.h index bcdea2b6b..a48710150 100644 --- a/src/tools/Pbc.h +++ b/src/tools/Pbc.h @@ -27,7 +27,7 @@ #include <vector> #include <cstddef> -namespace PLMD{ +namespace PLMD { /* Tool to deal with periodic boundary conditions. @@ -35,7 +35,7 @@ Tool to deal with periodic boundary conditions. This class is useful to apply periodic boundary conditions on interatomic distances. It stores privately information about reduced lattice vectors */ -class Pbc{ +class Pbc { /// Type of box enum {unset,orthorombic,generic} type; /// Box @@ -98,12 +98,12 @@ public: }; inline -Vector Pbc::distance(const Vector& v1,const Vector& v2)const{ +Vector Pbc::distance(const Vector& v1,const Vector& v2)const { return distance(v1,v2,NULL); } inline -bool Pbc::isSet()const{ +bool Pbc::isSet()const { return type!=unset; } diff --git a/src/tools/RMSD.cpp b/src/tools/RMSD.cpp index 481857670..0bc2eff54 100644 --- a/src/tools/RMSD.cpp +++ b/src/tools/RMSD.cpp @@ -27,45 +27,45 @@ #include <iostream> #include "Tools.h" using namespace std; -namespace PLMD{ +namespace PLMD { RMSD::RMSD() : alignmentMethod(SIMPLE),reference_center_is_calculated(false),reference_center_is_removed(false),positions_center_is_calculated(false),positions_center_is_removed(false) {} /// -/// general method to set all the rmsd property at once by using a pdb where occupancy column sets the weights for the atoms involved in the -/// alignment and beta sets the weight that are used for calculating the displacement. +/// general method to set all the rmsd property at once by using a pdb where occupancy column sets the weights for the atoms involved in the +/// alignment and beta sets the weight that are used for calculating the displacement. /// -void RMSD::set(const PDB&pdb, const string & mytype, bool remove_center, bool normalize_weights ){ +void RMSD::set(const PDB&pdb, const string & mytype, bool remove_center, bool normalize_weights ) { - set(pdb.getOccupancy(),pdb.getBeta(),pdb.getPositions(),mytype,remove_center,normalize_weights); + set(pdb.getOccupancy(),pdb.getBeta(),pdb.getPositions(),mytype,remove_center,normalize_weights); } -void RMSD::set(const std::vector<double> & align, const std::vector<double> & displace, const std::vector<Vector> & reference , const string & mytype, bool remove_center, bool normalize_weights ){ +void RMSD::set(const std::vector<double> & align, const std::vector<double> & displace, const std::vector<Vector> & reference, const string & mytype, bool remove_center, bool normalize_weights ) { - setReference(reference); // this by default remove the com and assumes uniform weights - setAlign(align, normalize_weights, remove_center); // this recalculates the com with weights. If remove_center=false then it restore the center back - setDisplace(displace, normalize_weights); // this is does not affect any calculation of the weights - setType(mytype); + setReference(reference); // this by default remove the com and assumes uniform weights + setAlign(align, normalize_weights, remove_center); // this recalculates the com with weights. If remove_center=false then it restore the center back + setDisplace(displace, normalize_weights); // this is does not affect any calculation of the weights + setType(mytype); } -void RMSD::setType(const string & mytype){ +void RMSD::setType(const string & mytype) { - alignmentMethod=SIMPLE; // initialize with the simplest case: no rotation - if (mytype=="SIMPLE"){ - alignmentMethod=SIMPLE; - } - else if (mytype=="OPTIMAL"){ - alignmentMethod=OPTIMAL; - } - else if (mytype=="OPTIMAL-FAST"){ - alignmentMethod=OPTIMAL_FAST; - } - else plumed_merror("unknown RMSD type" + mytype); + alignmentMethod=SIMPLE; // initialize with the simplest case: no rotation + if (mytype=="SIMPLE") { + alignmentMethod=SIMPLE; + } + else if (mytype=="OPTIMAL") { + alignmentMethod=OPTIMAL; + } + else if (mytype=="OPTIMAL-FAST") { + alignmentMethod=OPTIMAL_FAST; + } + else plumed_merror("unknown RMSD type" + mytype); } -void RMSD::clear(){ +void RMSD::clear() { reference.clear(); reference_center_is_calculated=false; reference_center_is_removed=false; @@ -75,98 +75,98 @@ void RMSD::clear(){ positions_center_is_removed=false; } -string RMSD::getMethod(){ - string mystring; - switch(alignmentMethod){ - case SIMPLE: mystring.assign("SIMPLE");break; - case OPTIMAL: mystring.assign("OPTIMAL");break; - case OPTIMAL_FAST: mystring.assign("OPTIMAL-FAST");break; - } - return mystring; +string RMSD::getMethod() { + string mystring; + switch(alignmentMethod) { + case SIMPLE: mystring.assign("SIMPLE"); break; + case OPTIMAL: mystring.assign("OPTIMAL"); break; + case OPTIMAL_FAST: mystring.assign("OPTIMAL-FAST"); break; + } + return mystring; } /// /// this calculates the center of mass for the reference and removes it from the reference itself /// considering uniform weights for alignment /// -void RMSD::setReference(const vector<Vector> & reference){ +void RMSD::setReference(const vector<Vector> & reference) { unsigned n=reference.size(); this->reference=reference; plumed_massert(align.empty(),"you should first clear() an RMSD object, then set a new reference"); plumed_massert(displace.empty(),"you should first clear() an RMSD object, then set a new reference"); align.resize(n,1.0/n); displace.resize(n,1.0/n); - for(unsigned i=0;i<n;i++) reference_center+=this->reference[i]*align[i]; - for(unsigned i=0;i<n;i++) this->reference[i]-=reference_center; + for(unsigned i=0; i<n; i++) reference_center+=this->reference[i]*align[i]; + for(unsigned i=0; i<n; i++) this->reference[i]-=reference_center; reference_center_is_calculated=true; reference_center_is_removed=true; } /// /// the alignment weights are here normalized to 1 and the center of the reference is removed accordingly /// -void RMSD::setAlign(const vector<double> & align, bool normalize_weights, bool remove_center){ +void RMSD::setAlign(const vector<double> & align, bool normalize_weights, bool remove_center) { unsigned n=reference.size(); plumed_massert(this->align.size()==align.size(),"mismatch in dimension of align/displace arrays"); this->align=align; - if(normalize_weights){ - double w=0.0; - for(unsigned i=0;i<n;i++) w+=this->align[i]; - double inv=1.0/w; - for(unsigned i=0;i<n;i++) this->align[i]*=inv; + if(normalize_weights) { + double w=0.0; + for(unsigned i=0; i<n; i++) w+=this->align[i]; + double inv=1.0/w; + for(unsigned i=0; i<n; i++) this->align[i]*=inv; } // recalculate the center anyway // just remove the center if that is asked // if the center was removed before, then add it and store the new one - if(reference_center_is_removed){ - plumed_massert(reference_center_is_calculated," seems that the reference center has been removed but not calculated and stored!"); - addCenter(reference,reference_center); + if(reference_center_is_removed) { + plumed_massert(reference_center_is_calculated," seems that the reference center has been removed but not calculated and stored!"); + addCenter(reference,reference_center); } reference_center=calculateCenter(reference,this->align); reference_center_is_calculated=true; - if(remove_center){ - removeCenter(reference,reference_center); - reference_center_is_removed=true; + if(remove_center) { + removeCenter(reference,reference_center); + reference_center_is_removed=true; } else { - reference_center_is_removed=false; + reference_center_is_removed=false; } } /// /// here the weigth for normalized weighths are normalized and set /// -void RMSD::setDisplace(const vector<double> & displace, bool normalize_weights){ +void RMSD::setDisplace(const vector<double> & displace, bool normalize_weights) { unsigned n=reference.size(); plumed_massert(this->displace.size()==displace.size(),"mismatch in dimension of align/displace arrays"); this->displace=displace; double w=0.0; - for(unsigned i=0;i<n;i++) w+=this->displace[i]; + for(unsigned i=0; i<n; i++) w+=this->displace[i]; double inv=1.0/w; - if(normalize_weights){for(unsigned i=0;i<n;i++) this->displace[i]*=inv;} + if(normalize_weights) {for(unsigned i=0; i<n; i++) this->displace[i]*=inv;} } /// /// This is the main workhorse for rmsd that decides to use specific optimal alignment versions /// -double RMSD::calculate(const std::vector<Vector> & positions,std::vector<Vector> &derivatives, bool squared)const{ +double RMSD::calculate(const std::vector<Vector> & positions,std::vector<Vector> &derivatives, bool squared)const { double ret=0.; - switch(alignmentMethod){ - case SIMPLE : { - // do a simple alignment without rotation - std::vector<Vector> displacement( derivatives.size() ); - ret=simpleAlignment(align,displace,positions,reference,derivatives,displacement,squared); - break; - } case OPTIMAL_FAST : { - // this is calling the fastest option: - if(align==displace) ret=optimalAlignment<false,true>(align,displace,positions,reference,derivatives,squared); - else ret=optimalAlignment<false,false>(align,displace,positions,reference,derivatives,squared); - break; - - } case OPTIMAL : { - // this is the fast routine but in the "safe" mode, which gives less numerical error: - if(align==displace) ret=optimalAlignment<true,true>(align,displace,positions,reference,derivatives,squared); - else ret=optimalAlignment<true,false>(align,displace,positions,reference,derivatives,squared); - break; - } - } + switch(alignmentMethod) { + case SIMPLE : { + // do a simple alignment without rotation + std::vector<Vector> displacement( derivatives.size() ); + ret=simpleAlignment(align,displace,positions,reference,derivatives,displacement,squared); + break; + } case OPTIMAL_FAST : { + // this is calling the fastest option: + if(align==displace) ret=optimalAlignment<false,true>(align,displace,positions,reference,derivatives,squared); + else ret=optimalAlignment<false,false>(align,displace,positions,reference,derivatives,squared); + break; + + } case OPTIMAL : { + // this is the fast routine but in the "safe" mode, which gives less numerical error: + if(align==displace) ret=optimalAlignment<true,true>(align,displace,positions,reference,derivatives,squared); + else ret=optimalAlignment<true,false>(align,displace,positions,reference,derivatives,squared); + break; + } + } return ret; @@ -174,116 +174,116 @@ double RMSD::calculate(const std::vector<Vector> & positions,std::vector<Vector> /// convenience method for calculating the standard derivatives and the derivative of the rmsd respect to the reference position -double RMSD::calc_DDistDRef( const std::vector<Vector>& positions, std::vector<Vector> &derivatives, std::vector<Vector>& DDistDRef , const bool squared ){ - double ret=0.; - switch(alignmentMethod){ - case SIMPLE: - plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n"); - break; - case OPTIMAL_FAST: - if(align==displace) ret=optimalAlignment_DDistDRef<false,true>(align,displace,positions,reference,derivatives,DDistDRef, squared); - else ret=optimalAlignment_DDistDRef<false,false>(align,displace,positions,reference,derivatives,DDistDRef,squared); - break; - case OPTIMAL: - if(align==displace) ret=optimalAlignment_DDistDRef<true,true>(align,displace,positions,reference,derivatives,DDistDRef,squared); - else ret=optimalAlignment_DDistDRef<true,false>(align,displace,positions,reference,derivatives,DDistDRef,squared); - break; - } +double RMSD::calc_DDistDRef( const std::vector<Vector>& positions, std::vector<Vector> &derivatives, std::vector<Vector>& DDistDRef, const bool squared ) { + double ret=0.; + switch(alignmentMethod) { + case SIMPLE: + plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n"); + break; + case OPTIMAL_FAST: + if(align==displace) ret=optimalAlignment_DDistDRef<false,true>(align,displace,positions,reference,derivatives,DDistDRef, squared); + else ret=optimalAlignment_DDistDRef<false,false>(align,displace,positions,reference,derivatives,DDistDRef,squared); + break; + case OPTIMAL: + if(align==displace) ret=optimalAlignment_DDistDRef<true,true>(align,displace,positions,reference,derivatives,DDistDRef,squared); + else ret=optimalAlignment_DDistDRef<true,false>(align,displace,positions,reference,derivatives,DDistDRef,squared); + break; + } return ret; } /// convenience method for calculating the standard derivatives and the derivative of the rmsd respect to the reference position without the matrix contribution /// as required by SOMA -double RMSD::calc_SOMA( const std::vector<Vector>& positions, std::vector<Vector> &derivatives, std::vector<Vector>& DDistDRef , const bool squared ){ - double ret=0.; - switch(alignmentMethod){ - case SIMPLE: - plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n"); - break; - case OPTIMAL_FAST: - if(align==displace) ret=optimalAlignment_SOMA<false,true>(align,displace,positions,reference,derivatives,DDistDRef, squared); - else ret=optimalAlignment_SOMA<false,false>(align,displace,positions,reference,derivatives,DDistDRef,squared); - break; - case OPTIMAL: - if(align==displace) ret=optimalAlignment_SOMA<true,true>(align,displace,positions,reference,derivatives,DDistDRef,squared); - else ret=optimalAlignment_SOMA<true,false>(align,displace,positions,reference,derivatives,DDistDRef,squared); - break; - } +double RMSD::calc_SOMA( const std::vector<Vector>& positions, std::vector<Vector> &derivatives, std::vector<Vector>& DDistDRef, const bool squared ) { + double ret=0.; + switch(alignmentMethod) { + case SIMPLE: + plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n"); + break; + case OPTIMAL_FAST: + if(align==displace) ret=optimalAlignment_SOMA<false,true>(align,displace,positions,reference,derivatives,DDistDRef, squared); + else ret=optimalAlignment_SOMA<false,false>(align,displace,positions,reference,derivatives,DDistDRef,squared); + break; + case OPTIMAL: + if(align==displace) ret=optimalAlignment_SOMA<true,true>(align,displace,positions,reference,derivatives,DDistDRef,squared); + else ret=optimalAlignment_SOMA<true,false>(align,displace,positions,reference,derivatives,DDistDRef,squared); + break; + } return ret; } -double RMSD::calc_DDistDRef_Rot_DRotDPos( const std::vector<Vector>& positions, std::vector<Vector> &derivatives, std::vector<Vector>& DDistDRef, Tensor & Rot, Matrix<std::vector<Vector> > &DRotDPos, const bool squared ){ - double ret=0.; - switch(alignmentMethod){ - case SIMPLE: - plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n"); - break; - case OPTIMAL_FAST: - if(align==displace) ret=optimalAlignment_DDistDRef_Rot_DRotDPos<false,true>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, squared); - else ret=optimalAlignment_DDistDRef_Rot_DRotDPos<false,false>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, squared); - break; - case OPTIMAL: - if(align==displace) ret=optimalAlignment_DDistDRef_Rot_DRotDPos<true,true>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, squared); - else ret=optimalAlignment_DDistDRef_Rot_DRotDPos<true,false>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, squared); - break; - } +double RMSD::calc_DDistDRef_Rot_DRotDPos( const std::vector<Vector>& positions, std::vector<Vector> &derivatives, std::vector<Vector>& DDistDRef, Tensor & Rot, Matrix<std::vector<Vector> > &DRotDPos, const bool squared ) { + double ret=0.; + switch(alignmentMethod) { + case SIMPLE: + plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n"); + break; + case OPTIMAL_FAST: + if(align==displace) ret=optimalAlignment_DDistDRef_Rot_DRotDPos<false,true>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, squared); + else ret=optimalAlignment_DDistDRef_Rot_DRotDPos<false,false>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, squared); + break; + case OPTIMAL: + if(align==displace) ret=optimalAlignment_DDistDRef_Rot_DRotDPos<true,true>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, squared); + else ret=optimalAlignment_DDistDRef_Rot_DRotDPos<true,false>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, squared); + break; + } return ret; } -double RMSD::calc_DDistDRef_Rot_DRotDPos_DRotDRef( const std::vector<Vector>& positions, std::vector<Vector> &derivatives, std::vector<Vector>& DDistDRef, Tensor & Rot, Matrix<std::vector<Vector> > &DRotDPos, Matrix<std::vector<Vector> > &DRotDRef, const bool squared ){ - double ret=0.; - switch(alignmentMethod){ - case SIMPLE: - plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n"); - break; - case OPTIMAL_FAST: - if(align==displace) ret=optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef<false,true>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, DRotDRef, squared); - else ret=optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef<false,false>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, DRotDRef, squared); - break; - case OPTIMAL: - if(align==displace) ret=optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef<true,true>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, DRotDRef, squared); - else ret=optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef<true,false>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, DRotDRef, squared); - break; - } +double RMSD::calc_DDistDRef_Rot_DRotDPos_DRotDRef( const std::vector<Vector>& positions, std::vector<Vector> &derivatives, std::vector<Vector>& DDistDRef, Tensor & Rot, Matrix<std::vector<Vector> > &DRotDPos, Matrix<std::vector<Vector> > &DRotDRef, const bool squared ) { + double ret=0.; + switch(alignmentMethod) { + case SIMPLE: + plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n"); + break; + case OPTIMAL_FAST: + if(align==displace) ret=optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef<false,true>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, DRotDRef, squared); + else ret=optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef<false,false>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, DRotDRef, squared); + break; + case OPTIMAL: + if(align==displace) ret=optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef<true,true>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, DRotDRef, squared); + else ret=optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef<true,false>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, DRotDRef, squared); + break; + } return ret; } double RMSD::calc_PCAelements( const std::vector<Vector>& positions, std::vector<Vector> &DDistDPos, Tensor & Rotation, Matrix<std::vector<Vector> > & DRotDPos,std::vector<Vector> & alignedpositions, std::vector<Vector> & centeredpositions, std::vector<Vector> ¢eredreference, const bool& squared ) const { - double ret=0.; - switch(alignmentMethod){ - case SIMPLE: - plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n"); - break; - case OPTIMAL_FAST: - if(align==displace) ret=optimalAlignment_PCA<false,true>(align,displace,positions,reference, alignedpositions, centeredpositions,centeredreference,Rotation,DDistDPos,DRotDPos,squared); - else ret=optimalAlignment_PCA<false,false>(align,displace,positions,reference, alignedpositions, centeredpositions,centeredreference,Rotation,DDistDPos,DRotDPos,squared); - break; - case OPTIMAL: - if(align==displace) ret=optimalAlignment_PCA<true,true>(align,displace,positions,reference, alignedpositions, centeredpositions,centeredreference,Rotation,DDistDPos,DRotDPos,squared); - else ret=optimalAlignment_PCA<true,false>(align,displace,positions,reference, alignedpositions, centeredpositions,centeredreference,Rotation,DDistDPos,DRotDPos,squared); - break; - } + double ret=0.; + switch(alignmentMethod) { + case SIMPLE: + plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n"); + break; + case OPTIMAL_FAST: + if(align==displace) ret=optimalAlignment_PCA<false,true>(align,displace,positions,reference, alignedpositions, centeredpositions,centeredreference,Rotation,DDistDPos,DRotDPos,squared); + else ret=optimalAlignment_PCA<false,false>(align,displace,positions,reference, alignedpositions, centeredpositions,centeredreference,Rotation,DDistDPos,DRotDPos,squared); + break; + case OPTIMAL: + if(align==displace) ret=optimalAlignment_PCA<true,true>(align,displace,positions,reference, alignedpositions, centeredpositions,centeredreference,Rotation,DDistDPos,DRotDPos,squared); + else ret=optimalAlignment_PCA<true,false>(align,displace,positions,reference, alignedpositions, centeredpositions,centeredreference,Rotation,DDistDPos,DRotDPos,squared); + break; + } return ret; } -double RMSD::calc_FitElements( const std::vector<Vector>& positions, Tensor & Rotation, Matrix<std::vector<Vector> > & DRotDPos, std::vector<Vector> & centeredpositions, Vector ¢er_positions, const bool& squared ){ - double ret=0.; - switch(alignmentMethod){ - case SIMPLE: - plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n"); - break; - case OPTIMAL_FAST: - if(align==displace)ret=optimalAlignment_Fit<false,true>(align,displace,positions,reference, Rotation,DRotDPos,centeredpositions,center_positions,squared); - else ret=optimalAlignment_Fit<false,false>(align,displace,positions,reference, Rotation,DRotDPos,centeredpositions,center_positions,squared); - break; - case OPTIMAL: - if(align==displace)ret=optimalAlignment_Fit<true,true>(align,displace,positions,reference,Rotation,DRotDPos,centeredpositions,center_positions,squared); - else ret=optimalAlignment_Fit<true,false>(align,displace,positions,reference,Rotation,DRotDPos,centeredpositions,center_positions,squared); - break; - } +double RMSD::calc_FitElements( const std::vector<Vector>& positions, Tensor & Rotation, Matrix<std::vector<Vector> > & DRotDPos, std::vector<Vector> & centeredpositions, Vector ¢er_positions, const bool& squared ) { + double ret=0.; + switch(alignmentMethod) { + case SIMPLE: + plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n"); + break; + case OPTIMAL_FAST: + if(align==displace)ret=optimalAlignment_Fit<false,true>(align,displace,positions,reference, Rotation,DRotDPos,centeredpositions,center_positions,squared); + else ret=optimalAlignment_Fit<false,false>(align,displace,positions,reference, Rotation,DRotDPos,centeredpositions,center_positions,squared); + break; + case OPTIMAL: + if(align==displace)ret=optimalAlignment_Fit<true,true>(align,displace,positions,reference,Rotation,DRotDPos,centeredpositions,center_positions,squared); + else ret=optimalAlignment_Fit<true,false>(align,displace,positions,reference,Rotation,DRotDPos,centeredpositions,center_positions,squared); + break; + } return ret; } @@ -293,58 +293,58 @@ double RMSD::calc_FitElements( const std::vector<Vector>& positions, Tensor & Ro double RMSD::simpleAlignment(const std::vector<double> & align, - const std::vector<double> & displace, - const std::vector<Vector> & positions, - const std::vector<Vector> & reference , - std::vector<Vector> & derivatives, - std::vector<Vector> & displacement, - bool squared)const{ - - double dist(0); - unsigned n=reference.size(); - - Vector apositions; - Vector areference; - Vector dpositions; - Vector dreference; - - for(unsigned i=0;i<n;i++){ - double aw=align[i]; - double dw=displace[i]; - apositions+=positions[i]*aw; - areference+=reference[i]*aw; - dpositions+=positions[i]*dw; - dreference+=reference[i]*dw; - } + const std::vector<double> & displace, + const std::vector<Vector> & positions, + const std::vector<Vector> & reference, + std::vector<Vector> & derivatives, + std::vector<Vector> & displacement, + bool squared)const { - Vector shift=((apositions-areference)-(dpositions-dreference)); - for(unsigned i=0;i<n;i++){ - displacement[i]=(positions[i]-apositions)-(reference[i]-areference); - dist+=displace[i]*displacement[i].modulo2(); - derivatives[i]=2*(displace[i]*displacement[i]+align[i]*shift); - } + double dist(0); + unsigned n=reference.size(); - if(!squared){ - // sqrt - dist=sqrt(dist); - ///// sqrt on derivatives - for(unsigned i=0;i<n;i++){derivatives[i]*=(0.5/dist);} - } - return dist; + Vector apositions; + Vector areference; + Vector dpositions; + Vector dreference; + + for(unsigned i=0; i<n; i++) { + double aw=align[i]; + double dw=displace[i]; + apositions+=positions[i]*aw; + areference+=reference[i]*aw; + dpositions+=positions[i]*dw; + dreference+=reference[i]*dw; + } + + Vector shift=((apositions-areference)-(dpositions-dreference)); + for(unsigned i=0; i<n; i++) { + displacement[i]=(positions[i]-apositions)-(reference[i]-areference); + dist+=displace[i]*displacement[i].modulo2(); + derivatives[i]=2*(displace[i]*displacement[i]+align[i]*shift); + } + + if(!squared) { + // sqrt + dist=sqrt(dist); + ///// sqrt on derivatives + for(unsigned i=0; i<n; i++) {derivatives[i]*=(0.5/dist);} + } + return dist; } // this below enable the standard case for rmsd where the rmsd is calculated and the derivative of rmsd respect to positions is retrieved -// additionally this assumes that the com of the reference is already subtracted. +// additionally this assumes that the com of the reference is already subtracted. #define OLDRMSD #ifdef OLDRMSD // notice that in the current implementation the safe argument only makes sense for // align==displace template <bool safe,bool alEqDis> double RMSD::optimalAlignment(const std::vector<double> & align, - const std::vector<double> & displace, - const std::vector<Vector> & positions, - const std::vector<Vector> & reference , - std::vector<Vector> & derivatives, bool squared)const{ + const std::vector<double> & displace, + const std::vector<Vector> & positions, + const std::vector<Vector> & reference, + std::vector<Vector> & derivatives, bool squared)const { double dist(0); const unsigned n=reference.size(); // This is the trace of positions*positions + reference*reference @@ -358,13 +358,13 @@ double RMSD::optimalAlignment(const std::vector<double> & align, Vector cpositions; // first expensive loop: compute centers - for(unsigned iat=0;iat<n;iat++){ + for(unsigned iat=0; iat<n; iat++) { double w=align[iat]; cpositions+=positions[iat]*w; } // second expensive loop: compute second moments wrt centers - for(unsigned iat=0;iat<n;iat++){ + for(unsigned iat=0; iat<n; iat++) { double w=align[iat]; rr00+=dotProduct(positions[iat]-cpositions,positions[iat]-cpositions)*w; rr11+=dotProduct(reference[iat],reference[iat])*w; @@ -390,7 +390,7 @@ double RMSD::optimalAlignment(const std::vector<double> & align, m[3][2] = m[2][3]; Tensor dm_drr01[4][4]; - if(!alEqDis){ + if(!alEqDis) { dm_drr01[0][0] = 2.0*Tensor(-1.0, 0.0, 0.0, 0.0,-1.0, 0.0, 0.0, 0.0,-1.0); dm_drr01[1][1] = 2.0*Tensor(-1.0, 0.0, 0.0, 0.0,+1.0, 0.0, 0.0, 0.0,+1.0); dm_drr01[2][2] = 2.0*Tensor(+1.0, 0.0, 0.0, 0.0,-1.0, 0.0, 0.0, 0.0,+1.0); @@ -413,7 +413,7 @@ double RMSD::optimalAlignment(const std::vector<double> & align, Matrix<double> eigenvecs; int diagerror=diagMat(m, eigenvals, eigenvecs ); - if (diagerror!=0){ + if (diagerror!=0) { string sdiagerror; Tools::convert(diagerror,sdiagerror); string msg="DIAGONALIZATION FAILED WITH ERROR CODE "+sdiagerror; @@ -427,20 +427,20 @@ double RMSD::optimalAlignment(const std::vector<double> & align, Vector4d q(eigenvecs[0][0],eigenvecs[0][1],eigenvecs[0][2],eigenvecs[0][3]); Tensor dq_drr01[4]; - if(!alEqDis){ + if(!alEqDis) { double dq_dm[4][4][4]; - for(unsigned i=0;i<4;i++) for(unsigned j=0;j<4;j++) for(unsigned k=0;k<4;k++){ - double tmp=0.0; + for(unsigned i=0; i<4; i++) for(unsigned j=0; j<4; j++) for(unsigned k=0; k<4; k++) { + double tmp=0.0; // perturbation theory for matrix m - for(unsigned l=1;l<4;l++) tmp+=eigenvecs[l][j]*eigenvecs[l][i]/(eigenvals[0]-eigenvals[l])*eigenvecs[0][k]; - dq_dm[i][j][k]=tmp; - } + for(unsigned l=1; l<4; l++) tmp+=eigenvecs[l][j]*eigenvecs[l][i]/(eigenvals[0]-eigenvals[l])*eigenvecs[0][k]; + dq_dm[i][j][k]=tmp; + } // propagation to _drr01 - for(unsigned i=0;i<4;i++){ + for(unsigned i=0; i<4; i++) { Tensor tmp; - for(unsigned j=0;j<4;j++) for(unsigned k=0;k<4;k++) { - tmp+=dq_dm[i][j][k]*dm_drr01[j][k]; - } + for(unsigned j=0; j<4; j++) for(unsigned k=0; k<4; k++) { + tmp+=dq_dm[i][j][k]*dm_drr01[j][k]; + } dq_drr01[i]=tmp; } } @@ -459,9 +459,9 @@ double RMSD::optimalAlignment(const std::vector<double> & align, rotation[2][0]=2*(+q[0]*q[2]+q[1]*q[3]); rotation[2][1]=2*(-q[0]*q[1]+q[2]*q[3]); - + Tensor drotation_drr01[3][3]; - if(!alEqDis){ + if(!alEqDis) { drotation_drr01[0][0]=2*q[0]*dq_drr01[0]+2*q[1]*dq_drr01[1]-2*q[2]*dq_drr01[2]-2*q[3]*dq_drr01[3]; drotation_drr01[1][1]=2*q[0]*dq_drr01[0]-2*q[1]*dq_drr01[1]+2*q[2]*dq_drr01[2]-2*q[3]*dq_drr01[3]; drotation_drr01[2][2]=2*q[0]*dq_drr01[0]-2*q[1]*dq_drr01[1]-2*q[2]*dq_drr01[2]+2*q[3]*dq_drr01[3]; @@ -488,13 +488,13 @@ double RMSD::optimalAlignment(const std::vector<double> & align, Vector ddist_dcpositions; // third expensive loop: derivatives - for(unsigned iat=0;iat<n;iat++){ + for(unsigned iat=0; iat<n; iat++) { Vector d(positions[iat]-cpositions - matmul(rotation,reference[iat])); - if(alEqDis){ + if(alEqDis) { // there is no need for derivatives of rotation and shift here as it is by construction zero // (similar to Hellman-Feynman forces) derivatives[iat]= prefactor*align[iat]*d; - if(safe) dist+=align[iat]*modulo2(d); + if(safe) dist+=align[iat]*modulo2(d); } else { // the case for align != displace is different, sob: dist+=displace[iat]*modulo2(d); @@ -507,276 +507,276 @@ double RMSD::optimalAlignment(const std::vector<double> & align, } } - if(!alEqDis){ + if(!alEqDis) { Tensor ddist_drr01; - for(unsigned i=0;i<3;i++) for(unsigned j=0;j<3;j++) ddist_drr01+=ddist_drotation[i][j]*drotation_drr01[i][j]; - for(unsigned iat=0;iat<n;iat++){ + for(unsigned i=0; i<3; i++) for(unsigned j=0; j<3; j++) ddist_drr01+=ddist_drotation[i][j]*drotation_drr01[i][j]; + for(unsigned iat=0; iat<n; iat++) { // this is propagating to positions. // I am implicitly using the derivative of rr01 wrt positions here derivatives[iat]+=matmul(ddist_drr01,reference[iat])*align[iat]; derivatives[iat]+=ddist_dcpositions*align[iat]; } } - if(!squared){ + if(!squared) { dist=sqrt(dist); - if(!alEqDis){ + if(!alEqDis) { double xx=0.5/dist; - for(unsigned iat=0;iat<n;iat++) derivatives[iat]*=xx; + for(unsigned iat=0; iat<n; iat++) derivatives[iat]*=xx; } } return dist; } #else -/// note that this method is intended to be repeatedly invoked +/// note that this method is intended to be repeatedly invoked /// when the reference does already have the center subtracted -/// but the position has not calculated center and not subtracted +/// but the position has not calculated center and not subtracted template <bool safe,bool alEqDis> double RMSD::optimalAlignment(const std::vector<double> & align, const std::vector<double> & displace, const std::vector<Vector> & positions, - const std::vector<Vector> & reference , - std::vector<Vector> & derivatives, + const std::vector<Vector> & reference, + std::vector<Vector> & derivatives, bool squared) const { - //std::cerr<<"setting up the core data \n"; - RMSDCoreData cd(align,displace,positions,reference); - - // transfer the settings for the center to let the CoreCalc deal with it - cd.setPositionsCenterIsRemoved(positions_center_is_removed); - if(positions_center_is_calculated){cd.setPositionsCenter(positions_center);} - else{cd.calcPositionsCenter();}; - - cd.setReferenceCenterIsRemoved(reference_center_is_removed); - if(!reference_center_is_calculated){cd.calcReferenceCenter();} - else{cd.setReferenceCenter(reference_center);} - - // Perform the diagonalization and all the needed stuff - cd.doCoreCalc(safe,alEqDis); - // make the core calc distance - double dist=cd.getDistance(squared); -// make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...) - derivatives=cd.getDDistanceDPositions(); - return dist; + //std::cerr<<"setting up the core data \n"; + RMSDCoreData cd(align,displace,positions,reference); + + // transfer the settings for the center to let the CoreCalc deal with it + cd.setPositionsCenterIsRemoved(positions_center_is_removed); + if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);} + else {cd.calcPositionsCenter();}; + + cd.setReferenceCenterIsRemoved(reference_center_is_removed); + if(!reference_center_is_calculated) {cd.calcReferenceCenter();} + else {cd.setReferenceCenter(reference_center);} + + // Perform the diagonalization and all the needed stuff + cd.doCoreCalc(safe,alEqDis); + // make the core calc distance + double dist=cd.getDistance(squared); +// make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...) + derivatives=cd.getDDistanceDPositions(); + return dist; } #endif template <bool safe,bool alEqDis> double RMSD::optimalAlignment_DDistDRef(const std::vector<double> & align, - const std::vector<double> & displace, - const std::vector<Vector> & positions, - const std::vector<Vector> & reference , - std::vector<Vector> & derivatives, - std::vector<Vector> & ddistdref, - bool squared) const { - //initialize the data into the structure - // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business - RMSDCoreData cd(align,displace,positions,reference); - // transfer the settings for the center to let the CoreCalc deal with it - // transfer the settings for the center to let the CoreCalc deal with it - cd.setPositionsCenterIsRemoved(positions_center_is_removed); - if(positions_center_is_calculated){cd.setPositionsCenter(positions_center);} - else{cd.calcPositionsCenter();}; - - cd.setReferenceCenterIsRemoved(reference_center_is_removed); - if(!reference_center_is_calculated){cd.calcReferenceCenter();} - else{cd.setReferenceCenter(reference_center);} - - // Perform the diagonalization and all the needed stuff - cd.doCoreCalc(safe,alEqDis); - // make the core calc distance - double dist=cd.getDistance(squared); -// make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...) - derivatives=cd.getDDistanceDPositions(); - ddistdref=cd.getDDistanceDReference(); - return dist; + const std::vector<double> & displace, + const std::vector<Vector> & positions, + const std::vector<Vector> & reference, + std::vector<Vector> & derivatives, + std::vector<Vector> & ddistdref, + bool squared) const { + //initialize the data into the structure + // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business + RMSDCoreData cd(align,displace,positions,reference); + // transfer the settings for the center to let the CoreCalc deal with it + // transfer the settings for the center to let the CoreCalc deal with it + cd.setPositionsCenterIsRemoved(positions_center_is_removed); + if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);} + else {cd.calcPositionsCenter();}; + + cd.setReferenceCenterIsRemoved(reference_center_is_removed); + if(!reference_center_is_calculated) {cd.calcReferenceCenter();} + else {cd.setReferenceCenter(reference_center);} + + // Perform the diagonalization and all the needed stuff + cd.doCoreCalc(safe,alEqDis); + // make the core calc distance + double dist=cd.getDistance(squared); +// make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...) + derivatives=cd.getDDistanceDPositions(); + ddistdref=cd.getDDistanceDReference(); + return dist; } template <bool safe,bool alEqDis> double RMSD::optimalAlignment_SOMA(const std::vector<double> & align, - const std::vector<double> & displace, - const std::vector<Vector> & positions, - const std::vector<Vector> & reference , - std::vector<Vector> & derivatives, - std::vector<Vector> & ddistdref, - bool squared) const { - //initialize the data into the structure - // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business - RMSDCoreData cd(align,displace,positions,reference); - // transfer the settings for the center to let the CoreCalc deal with it - // transfer the settings for the center to let the CoreCalc deal with it - cd.setPositionsCenterIsRemoved(positions_center_is_removed); - if(positions_center_is_calculated){cd.setPositionsCenter(positions_center);} - else{cd.calcPositionsCenter();}; - - cd.setReferenceCenterIsRemoved(reference_center_is_removed); - if(!reference_center_is_calculated){cd.calcReferenceCenter();} - else{cd.setReferenceCenter(reference_center);} - - // Perform the diagonalization and all the needed stuff - cd.doCoreCalc(safe,alEqDis); - // make the core calc distance - double dist=cd.getDistance(squared); -// make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...) - derivatives=cd.getDDistanceDPositions(); - ddistdref=cd.getDDistanceDReferenceSOMA(); - return dist; + const std::vector<double> & displace, + const std::vector<Vector> & positions, + const std::vector<Vector> & reference, + std::vector<Vector> & derivatives, + std::vector<Vector> & ddistdref, + bool squared) const { + //initialize the data into the structure + // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business + RMSDCoreData cd(align,displace,positions,reference); + // transfer the settings for the center to let the CoreCalc deal with it + // transfer the settings for the center to let the CoreCalc deal with it + cd.setPositionsCenterIsRemoved(positions_center_is_removed); + if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);} + else {cd.calcPositionsCenter();}; + + cd.setReferenceCenterIsRemoved(reference_center_is_removed); + if(!reference_center_is_calculated) {cd.calcReferenceCenter();} + else {cd.setReferenceCenter(reference_center);} + + // Perform the diagonalization and all the needed stuff + cd.doCoreCalc(safe,alEqDis); + // make the core calc distance + double dist=cd.getDistance(squared); +// make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...) + derivatives=cd.getDDistanceDPositions(); + ddistdref=cd.getDDistanceDReferenceSOMA(); + return dist; } template <bool safe,bool alEqDis> double RMSD::optimalAlignment_DDistDRef_Rot_DRotDPos(const std::vector<double> & align, - const std::vector<double> & displace, - const std::vector<Vector> & positions, - const std::vector<Vector> & reference , - std::vector<Vector> & derivatives, - std::vector<Vector> & ddistdref, - Tensor & Rotation, - Matrix<std::vector<Vector> > &DRotDPos, - bool squared) const { - //initialize the data into the structure - // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business - RMSDCoreData cd(align,displace,positions,reference); - // transfer the settings for the center to let the CoreCalc deal with it - // transfer the settings for the center to let the CoreCalc deal with it - cd.setPositionsCenterIsRemoved(positions_center_is_removed); - if(positions_center_is_calculated){cd.setPositionsCenter(positions_center);} - else{cd.calcPositionsCenter();}; - - cd.setReferenceCenterIsRemoved(reference_center_is_removed); - if(!reference_center_is_calculated){cd.calcReferenceCenter();} - else{cd.setReferenceCenter(reference_center);} - - // Perform the diagonalization and all the needed stuff - cd.doCoreCalc(safe,alEqDis); - // make the core calc distance - double dist=cd.getDistance(squared); -// make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...) - derivatives=cd.getDDistanceDPositions(); - ddistdref=cd.getDDistanceDReference(); - // get the rotation matrix - Rotation=cd.getRotationMatrixReferenceToPositions(); - // get its derivative - DRotDPos=cd.getDRotationDPositions(); - return dist; + const std::vector<double> & displace, + const std::vector<Vector> & positions, + const std::vector<Vector> & reference, + std::vector<Vector> & derivatives, + std::vector<Vector> & ddistdref, + Tensor & Rotation, + Matrix<std::vector<Vector> > &DRotDPos, + bool squared) const { + //initialize the data into the structure + // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business + RMSDCoreData cd(align,displace,positions,reference); + // transfer the settings for the center to let the CoreCalc deal with it + // transfer the settings for the center to let the CoreCalc deal with it + cd.setPositionsCenterIsRemoved(positions_center_is_removed); + if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);} + else {cd.calcPositionsCenter();}; + + cd.setReferenceCenterIsRemoved(reference_center_is_removed); + if(!reference_center_is_calculated) {cd.calcReferenceCenter();} + else {cd.setReferenceCenter(reference_center);} + + // Perform the diagonalization and all the needed stuff + cd.doCoreCalc(safe,alEqDis); + // make the core calc distance + double dist=cd.getDistance(squared); +// make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...) + derivatives=cd.getDDistanceDPositions(); + ddistdref=cd.getDDistanceDReference(); + // get the rotation matrix + Rotation=cd.getRotationMatrixReferenceToPositions(); + // get its derivative + DRotDPos=cd.getDRotationDPositions(); + return dist; } template <bool safe,bool alEqDis> double RMSD::optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef(const std::vector<double> & align, - const std::vector<double> & displace, - const std::vector<Vector> & positions, - const std::vector<Vector> & reference , - std::vector<Vector> & derivatives, - std::vector<Vector> & ddistdref, - Tensor & Rotation, - Matrix<std::vector<Vector> > &DRotDPos, - Matrix<std::vector<Vector> > &DRotDRef, - bool squared) const { - //initialize the data into the structure - // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business - RMSDCoreData cd(align,displace,positions,reference); - // transfer the settings for the center to let the CoreCalc deal with it - // transfer the settings for the center to let the CoreCalc deal with it - cd.setPositionsCenterIsRemoved(positions_center_is_removed); - if(positions_center_is_calculated){cd.setPositionsCenter(positions_center);} - else{cd.calcPositionsCenter();}; - - cd.setReferenceCenterIsRemoved(reference_center_is_removed); - if(!reference_center_is_calculated){cd.calcReferenceCenter();} - else{cd.setReferenceCenter(reference_center);} - - // Perform the diagonalization and all the needed stuff - cd.doCoreCalc(safe,alEqDis); - // make the core calc distance - double dist=cd.getDistance(squared); -// make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...) - derivatives=cd.getDDistanceDPositions(); - ddistdref=cd.getDDistanceDReference(); - // get the rotation matrix - Rotation=cd.getRotationMatrixReferenceToPositions(); - // get its derivative - DRotDPos=cd.getDRotationDPositions(); - DRotDRef=cd.getDRotationDReference(); - return dist; + const std::vector<double> & displace, + const std::vector<Vector> & positions, + const std::vector<Vector> & reference, + std::vector<Vector> & derivatives, + std::vector<Vector> & ddistdref, + Tensor & Rotation, + Matrix<std::vector<Vector> > &DRotDPos, + Matrix<std::vector<Vector> > &DRotDRef, + bool squared) const { + //initialize the data into the structure + // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business + RMSDCoreData cd(align,displace,positions,reference); + // transfer the settings for the center to let the CoreCalc deal with it + // transfer the settings for the center to let the CoreCalc deal with it + cd.setPositionsCenterIsRemoved(positions_center_is_removed); + if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);} + else {cd.calcPositionsCenter();}; + + cd.setReferenceCenterIsRemoved(reference_center_is_removed); + if(!reference_center_is_calculated) {cd.calcReferenceCenter();} + else {cd.setReferenceCenter(reference_center);} + + // Perform the diagonalization and all the needed stuff + cd.doCoreCalc(safe,alEqDis); + // make the core calc distance + double dist=cd.getDistance(squared); +// make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...) + derivatives=cd.getDDistanceDPositions(); + ddistdref=cd.getDDistanceDReference(); + // get the rotation matrix + Rotation=cd.getRotationMatrixReferenceToPositions(); + // get its derivative + DRotDPos=cd.getDRotationDPositions(); + DRotDRef=cd.getDRotationDReference(); + return dist; } template <bool safe,bool alEqDis> double RMSD::optimalAlignment_PCA(const std::vector<double> & align, - const std::vector<double> & displace, - const std::vector<Vector> & positions, - const std::vector<Vector> & reference, - std::vector<Vector> & alignedpositions, - std::vector<Vector> & centeredpositions, - std::vector<Vector> & centeredreference, - Tensor & Rotation, - std::vector<Vector> & DDistDPos, - Matrix<std::vector<Vector> > & DRotDPos, - bool squared) const { - //initialize the data into the structure - // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business - RMSDCoreData cd(align,displace,positions,reference); - // transfer the settings for the center to let the CoreCalc deal with it - cd.setPositionsCenterIsRemoved(positions_center_is_removed); - if(positions_center_is_calculated){cd.setPositionsCenter(positions_center);} - else{cd.calcPositionsCenter();}; - - cd.setReferenceCenterIsRemoved(reference_center_is_removed); - if(!reference_center_is_calculated){cd.calcReferenceCenter();} - else{cd.setReferenceCenter(reference_center);} - - // Perform the diagonalization and all the needed stuff - cd.doCoreCalc(safe,alEqDis); - // make the core calc distance - double dist=cd.getDistance(squared); - // make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...) - DDistDPos=cd.getDDistanceDPositions(); - // get the rotation matrix - Rotation=cd.getRotationMatrixPositionsToReference(); - // get its derivative - DRotDPos=cd.getDRotationDPositions(true); // this gives back the inverse - // get aligned positions - alignedpositions=cd.getAlignedPositionsToReference(); - // get centered positions - centeredpositions=cd.getCenteredPositions(); - // get centered reference - centeredreference=cd.getCenteredReference(); - return dist; + const std::vector<double> & displace, + const std::vector<Vector> & positions, + const std::vector<Vector> & reference, + std::vector<Vector> & alignedpositions, + std::vector<Vector> & centeredpositions, + std::vector<Vector> & centeredreference, + Tensor & Rotation, + std::vector<Vector> & DDistDPos, + Matrix<std::vector<Vector> > & DRotDPos, + bool squared) const { + //initialize the data into the structure + // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business + RMSDCoreData cd(align,displace,positions,reference); + // transfer the settings for the center to let the CoreCalc deal with it + cd.setPositionsCenterIsRemoved(positions_center_is_removed); + if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);} + else {cd.calcPositionsCenter();}; + + cd.setReferenceCenterIsRemoved(reference_center_is_removed); + if(!reference_center_is_calculated) {cd.calcReferenceCenter();} + else {cd.setReferenceCenter(reference_center);} + + // Perform the diagonalization and all the needed stuff + cd.doCoreCalc(safe,alEqDis); + // make the core calc distance + double dist=cd.getDistance(squared); + // make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...) + DDistDPos=cd.getDDistanceDPositions(); + // get the rotation matrix + Rotation=cd.getRotationMatrixPositionsToReference(); + // get its derivative + DRotDPos=cd.getDRotationDPositions(true); // this gives back the inverse + // get aligned positions + alignedpositions=cd.getAlignedPositionsToReference(); + // get centered positions + centeredpositions=cd.getCenteredPositions(); + // get centered reference + centeredreference=cd.getCenteredReference(); + return dist; } template <bool safe,bool alEqDis> double RMSD::optimalAlignment_Fit(const std::vector<double> & align, - const std::vector<double> & displace, - const std::vector<Vector> & positions, - const std::vector<Vector> & reference, - Tensor & Rotation, - Matrix<std::vector<Vector> > & DRotDPos, - std::vector<Vector> & centeredpositions, - Vector & center_positions, - bool squared){ - //initialize the data into the structure - // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business - RMSDCoreData cd(align,displace,positions,reference); - // transfer the settings for the center to let the CoreCalc deal with it - cd.setPositionsCenterIsRemoved(positions_center_is_removed); - if(positions_center_is_calculated){cd.setPositionsCenter(positions_center);} - else{cd.calcPositionsCenter();}; - - cd.setReferenceCenterIsRemoved(reference_center_is_removed); - if(!reference_center_is_calculated){cd.calcReferenceCenter();} - else{cd.setReferenceCenter(reference_center);} - - // Perform the diagonalization and all the needed stuff - cd.doCoreCalc(safe,alEqDis); - // make the core calc distance - double dist=cd.getDistance(squared); - // get the rotation matrix - Rotation=cd.getRotationMatrixPositionsToReference(); - // get its derivative - DRotDPos=cd.getDRotationDPositions(true); // this gives back the inverse - // get centered positions - centeredpositions=cd.getCenteredPositions(); + const std::vector<double> & displace, + const std::vector<Vector> & positions, + const std::vector<Vector> & reference, + Tensor & Rotation, + Matrix<std::vector<Vector> > & DRotDPos, + std::vector<Vector> & centeredpositions, + Vector & center_positions, + bool squared) { + //initialize the data into the structure + // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business + RMSDCoreData cd(align,displace,positions,reference); + // transfer the settings for the center to let the CoreCalc deal with it + cd.setPositionsCenterIsRemoved(positions_center_is_removed); + if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);} + else {cd.calcPositionsCenter();}; + + cd.setReferenceCenterIsRemoved(reference_center_is_removed); + if(!reference_center_is_calculated) {cd.calcReferenceCenter();} + else {cd.setReferenceCenter(reference_center);} + + // Perform the diagonalization and all the needed stuff + cd.doCoreCalc(safe,alEqDis); + // make the core calc distance + double dist=cd.getDistance(squared); + // get the rotation matrix + Rotation=cd.getRotationMatrixPositionsToReference(); + // get its derivative + DRotDPos=cd.getDRotationDPositions(true); // this gives back the inverse + // get centered positions + centeredpositions=cd.getCenteredPositions(); // get center - center_positions=cd.getPositionsCenter(); - return dist; + center_positions=cd.getPositionsCenter(); + return dist; } @@ -786,27 +786,27 @@ double RMSD::optimalAlignment_Fit(const std::vector<double> & align, /// This calculates the elements needed by the quaternion to calculate everything that is needed /// additional calls retrieve different components -/// note that this considers that the centers of both reference and positions are already setted -/// but automatically should properly account for non removed components: if not removed then it -/// removes prior to calculation of the alignment -void RMSDCoreData::doCoreCalc(bool safe,bool alEqDis, bool only_rotation){ +/// note that this considers that the centers of both reference and positions are already setted +/// but automatically should properly account for non removed components: if not removed then it +/// removes prior to calculation of the alignment +void RMSDCoreData::doCoreCalc(bool safe,bool alEqDis, bool only_rotation) { retrieve_only_rotation=only_rotation; const unsigned n=static_cast<unsigned int>(reference.size()); - - plumed_massert(creference_is_calculated,"the center of the reference frame must be already provided at this stage"); - plumed_massert(cpositions_is_calculated,"the center of the positions frame must be already provided at this stage"); + + plumed_massert(creference_is_calculated,"the center of the reference frame must be already provided at this stage"); + plumed_massert(cpositions_is_calculated,"the center of the positions frame must be already provided at this stage"); // This is the trace of positions*positions + reference*reference rr00=0.; rr11=0.; // This is positions*reference Tensor rr01; -// center of mass managing: must subtract the center from the position or not? +// center of mass managing: must subtract the center from the position or not? Vector cp; cp.zero(); if(!cpositions_is_removed)cp=cpositions; Vector cr; cr.zero(); if(!creference_is_removed)cr=creference; // second expensive loop: compute second moments wrt centers - for(unsigned iat=0;iat<n;iat++){ + for(unsigned iat=0; iat<n; iat++) { double w=align[iat]; rr00+=dotProduct(positions[iat]-cp,positions[iat]-cp)*w; rr11+=dotProduct(reference[iat]-cr,reference[iat]-cr)*w; @@ -833,10 +833,10 @@ void RMSDCoreData::doCoreCalc(bool safe,bool alEqDis, bool only_rotation){ m[3][1] = m[1][3]; m[3][2] = m[2][3]; - + Tensor dm_drr01[4][4]; - if(!alEqDis or !retrieve_only_rotation){ - dm_drr01[0][0] = 2.0*Tensor(-1.0, 0.0, 0.0, 0.0,-1.0, 0.0, 0.0, 0.0,-1.0); + if(!alEqDis or !retrieve_only_rotation) { + dm_drr01[0][0] = 2.0*Tensor(-1.0, 0.0, 0.0, 0.0,-1.0, 0.0, 0.0, 0.0,-1.0); dm_drr01[1][1] = 2.0*Tensor(-1.0, 0.0, 0.0, 0.0,+1.0, 0.0, 0.0, 0.0,+1.0); dm_drr01[2][2] = 2.0*Tensor(+1.0, 0.0, 0.0, 0.0,-1.0, 0.0, 0.0, 0.0,+1.0); dm_drr01[3][3] = 2.0*Tensor(+1.0, 0.0, 0.0, 0.0,+1.0, 0.0, 0.0, 0.0,-1.0); @@ -857,7 +857,7 @@ void RMSDCoreData::doCoreCalc(bool safe,bool alEqDis, bool only_rotation){ int diagerror=diagMat(m, eigenvals, eigenvecs ); - if (diagerror!=0){ + if (diagerror!=0) { std::string sdiagerror; Tools::convert(diagerror,sdiagerror); std::string msg="DIAGONALIZATION FAILED WITH ERROR CODE "+sdiagerror; @@ -868,20 +868,20 @@ void RMSDCoreData::doCoreCalc(bool safe,bool alEqDis, bool only_rotation){ // cerr<<"EIGENVAL "<<eigenvals[0]<<" "<<eigenvals[1]<<" "<<eigenvals[2]<<" "<<eigenvals[3]<<"\n"; Tensor dq_drr01[4]; - if(!alEqDis or !only_rotation){ + if(!alEqDis or !only_rotation) { double dq_dm[4][4][4]; - for(unsigned i=0;i<4;i++) for(unsigned j=0;j<4;j++) for(unsigned k=0;k<4;k++){ - double tmp=0.0; + for(unsigned i=0; i<4; i++) for(unsigned j=0; j<4; j++) for(unsigned k=0; k<4; k++) { + double tmp=0.0; // perturbation theory for matrix m - for(unsigned l=1;l<4;l++) tmp+=eigenvecs[l][j]*eigenvecs[l][i]/(eigenvals[0]-eigenvals[l])*eigenvecs[0][k]; - dq_dm[i][j][k]=tmp; - } + for(unsigned l=1; l<4; l++) tmp+=eigenvecs[l][j]*eigenvecs[l][i]/(eigenvals[0]-eigenvals[l])*eigenvecs[0][k]; + dq_dm[i][j][k]=tmp; + } // propagation to _drr01 - for(unsigned i=0;i<4;i++){ + for(unsigned i=0; i<4; i++) { Tensor tmp; - for(unsigned j=0;j<4;j++) for(unsigned k=0;k<4;k++) { - tmp+=dq_dm[i][j][k]*dm_drr01[j][k]; - } + for(unsigned j=0; j<4; j++) for(unsigned k=0; k<4; k++) { + tmp+=dq_dm[i][j][k]*dm_drr01[j][k]; + } dq_drr01[i]=tmp; } } @@ -898,9 +898,9 @@ void RMSDCoreData::doCoreCalc(bool safe,bool alEqDis, bool only_rotation){ rotation[1][0]=2*(-q[0]*q[3]+q[1]*q[2]); rotation[2][0]=2*(+q[0]*q[2]+q[1]*q[3]); rotation[2][1]=2*(-q[0]*q[1]+q[2]*q[3]); - - - if(!alEqDis or !only_rotation){ + + + if(!alEqDis or !only_rotation) { drotation_drr01[0][0]=2*q[0]*dq_drr01[0]+2*q[1]*dq_drr01[1]-2*q[2]*dq_drr01[2]-2*q[3]*dq_drr01[3]; drotation_drr01[1][1]=2*q[0]*dq_drr01[0]-2*q[1]*dq_drr01[1]+2*q[2]*dq_drr01[2]-2*q[3]*dq_drr01[3]; drotation_drr01[2][2]=2*q[0]*dq_drr01[0]-2*q[1]*dq_drr01[1]-2*q[2]*dq_drr01[2]+2*q[3]*dq_drr01[3]; @@ -916,51 +916,51 @@ void RMSDCoreData::doCoreCalc(bool safe,bool alEqDis, bool only_rotation){ // calculate rotation matrix derivatives and components distances needed for components only when align!=displacement if(!alEqDis)ddist_drotation.zero(); - for(unsigned iat=0;iat<n;iat++){ + for(unsigned iat=0; iat<n; iat++) { // components differences: this is useful externally - d[iat]=positions[iat]-cp - matmul(rotation,reference[iat]-cr); - //cerr<<"D "<<iat<<" "<<d[iat][0]<<" "<<d[iat][1]<<" "<<d[iat][2]<<"\n"; + d[iat]=positions[iat]-cp - matmul(rotation,reference[iat]-cr); + //cerr<<"D "<<iat<<" "<<d[iat][0]<<" "<<d[iat][1]<<" "<<d[iat][2]<<"\n"; // ddist_drotation if needed if(!alEqDis or !only_rotation) ddist_drotation+=-2*displace[iat]*extProduct(d[iat],reference[iat]-cr); } - if(!alEqDis or !only_rotation){ - ddist_drr01.zero(); - for(unsigned i=0;i<3;i++) for(unsigned j=0;j<3;j++) ddist_drr01+=ddist_drotation[i][j]*drotation_drr01[i][j]; + if(!alEqDis or !only_rotation) { + ddist_drr01.zero(); + for(unsigned i=0; i<3; i++) for(unsigned j=0; j<3; j++) ddist_drr01+=ddist_drotation[i][j]*drotation_drr01[i][j]; } // transfer this bools to the cd so that this settings will be reflected in the other calls - this->alEqDis=alEqDis; - this->safe=safe; + this->alEqDis=alEqDis; + this->safe=safe; isInitialized=true; } /// just retrieve the distance already calculated -double RMSDCoreData::getDistance( bool squared){ +double RMSDCoreData::getDistance( bool squared) { if(!isInitialized)plumed_merror("getDistance cannot calculate the distance without being initialized first by doCoreCalc "); dist=eigenvals[0]+rr00+rr11; - + if(safe || !alEqDis) dist=0.0; const unsigned n=static_cast<unsigned int>(reference.size()); - for(unsigned iat=0;iat<n;iat++){ - if(alEqDis){ - if(safe) dist+=align[iat]*modulo2(d[iat]); - } else { - dist+=displace[iat]*modulo2(d[iat]); - } + for(unsigned iat=0; iat<n; iat++) { + if(alEqDis) { + if(safe) dist+=align[iat]*modulo2(d[iat]); + } else { + dist+=displace[iat]*modulo2(d[iat]); + } } - if(!squared){ - dist=sqrt(dist); - distanceIsMSD=false; - }else{ - distanceIsMSD=true; + if(!squared) { + dist=sqrt(dist); + distanceIsMSD=false; + } else { + distanceIsMSD=true; } hasDistance=true; - return dist; + return dist; } -std::vector<Vector> RMSDCoreData::getDDistanceDPositions(){ +std::vector<Vector> RMSDCoreData::getDDistanceDPositions() { std::vector<Vector> derivatives; const unsigned n=static_cast<unsigned int>(reference.size()); Vector ddist_dcpositions; @@ -972,8 +972,8 @@ std::vector<Vector> RMSDCoreData::getDDistanceDPositions(){ if(!isInitialized)plumed_merror("getDPositionsDerivatives needs to initialize the coreData first!"); Vector csum; Vector tmp1,tmp2; - for(unsigned iat=0;iat<n;iat++){ - if(alEqDis){ + for(unsigned iat=0; iat<n; iat++) { + if(alEqDis) { // there is no need for derivatives of rotation and shift here as it is by construction zero // (similar to Hellman-Feynman forces) derivatives[iat]= 2*prefactor*align[iat]*d[iat]; @@ -984,18 +984,18 @@ std::vector<Vector> RMSDCoreData::getDDistanceDPositions(){ // derivative of cpositions ddist_dcpositions+=-tmp1; // these needed for com corrections - tmp2=matmul(ddist_drr01,reference[iat]-creference)*align[iat]; - derivatives[iat]+=tmp2; + tmp2=matmul(ddist_drr01,reference[iat]-creference)*align[iat]; + derivatives[iat]+=tmp2; csum+=tmp2; } } - if(!alEqDis) for(unsigned iat=0;iat<n;iat++){derivatives[iat]= prefactor*(derivatives[iat]+(ddist_dcpositions-csum)*align[iat]); } + if(!alEqDis) for(unsigned iat=0; iat<n; iat++) {derivatives[iat]= prefactor*(derivatives[iat]+(ddist_dcpositions-csum)*align[iat]); } return derivatives; } -std::vector<Vector> RMSDCoreData::getDDistanceDReference(){ +std::vector<Vector> RMSDCoreData::getDDistanceDReference() { std::vector<Vector> derivatives; const unsigned n=static_cast<unsigned int>(reference.size()); Vector ddist_dcreference; @@ -1009,14 +1009,14 @@ std::vector<Vector> RMSDCoreData::getDDistanceDReference(){ if(!isInitialized)plumed_merror("getDDistanceDReference to initialize the coreData first!"); // get the transpose rotation Tensor t_rotation=rotation.transpose(); - Tensor t_ddist_drr01=ddist_drr01.transpose(); - + Tensor t_ddist_drr01=ddist_drr01.transpose(); + // third expensive loop: derivatives - for(unsigned iat=0;iat<n;iat++){ - if(alEqDis){ + for(unsigned iat=0; iat<n; iat++) { + if(alEqDis) { // there is no need for derivatives of rotation and shift here as it is by construction zero // (similar to Hellman-Feynman forces) - //TODO: check this derivative down here + //TODO: check this derivative down here derivatives[iat]= -2*prefactor*align[iat]*matmul(t_rotation,d[iat]); } else { // these are the derivatives assuming the roto-translation as frozen @@ -1026,18 +1026,18 @@ std::vector<Vector> RMSDCoreData::getDDistanceDReference(){ ddist_dcreference+=tmp1; // these below are needed for com correction tmp2=matmul(t_ddist_drr01,positions[iat]-cpositions)*align[iat]; - derivatives[iat]+=tmp2; - csum+=tmp2; + derivatives[iat]+=tmp2; + csum+=tmp2; } } - if(!alEqDis) for(unsigned iat=0;iat<n;iat++){derivatives[iat]= prefactor*(derivatives[iat]+(ddist_dcreference-csum)*align[iat]);} + if(!alEqDis) for(unsigned iat=0; iat<n; iat++) {derivatives[iat]= prefactor*(derivatives[iat]+(ddist_dcreference-csum)*align[iat]);} return derivatives; } /// this version does not calculate the derivative of rotation matrix as needed for SOMA -std::vector<Vector> RMSDCoreData::getDDistanceDReferenceSOMA(){ +std::vector<Vector> RMSDCoreData::getDDistanceDReferenceSOMA() { std::vector<Vector> derivatives; const unsigned n=static_cast<unsigned int>(reference.size()); Vector ddist_dcreference; @@ -1051,13 +1051,13 @@ std::vector<Vector> RMSDCoreData::getDDistanceDReferenceSOMA(){ if(!isInitialized)plumed_merror("getDDistanceDReference to initialize the coreData first!"); // get the transpose rotation Tensor t_rotation=rotation.transpose(); - + // third expensive loop: derivatives - for(unsigned iat=0;iat<n;iat++){ - if(alEqDis){ + for(unsigned iat=0; iat<n; iat++) { + if(alEqDis) { // there is no need for derivatives of rotation and shift here as it is by construction zero // (similar to Hellman-Feynman forces) - //TODO: check this derivative down here + //TODO: check this derivative down here derivatives[iat]= -2*prefactor*align[iat]*matmul(t_rotation,d[iat]); } else { // these are the derivatives assuming the roto-translation as frozen @@ -1068,7 +1068,7 @@ std::vector<Vector> RMSDCoreData::getDDistanceDReferenceSOMA(){ } } - if(!alEqDis) for(unsigned iat=0;iat<n;iat++)derivatives[iat]=prefactor*(derivatives[iat]+ddist_dcreference*align[iat]); + if(!alEqDis) for(unsigned iat=0; iat<n; iat++)derivatives[iat]=prefactor*(derivatives[iat]+ddist_dcreference*align[iat]); return derivatives; } @@ -1081,34 +1081,34 @@ respect to positions note that the this transformation overlap the reference onto position if inverseTransform=true then aligns the positions onto reference */ -Matrix<std::vector<Vector> > RMSDCoreData::getDRotationDPositions( bool inverseTransform ){ +Matrix<std::vector<Vector> > RMSDCoreData::getDRotationDPositions( bool inverseTransform ) { const unsigned n=static_cast<unsigned int>(reference.size()); plumed_massert(!retrieve_only_rotation,"You used only_rotation=true in doCoreCalc therefore you cannot retrieve this information now"); if(!isInitialized)plumed_merror("getDRotationDPosition to initialize the coreData first!"); - Matrix<std::vector<Vector> > DRotDPos=Matrix<std::vector<Vector> >(3,3); + Matrix<std::vector<Vector> > DRotDPos=Matrix<std::vector<Vector> >(3,3); // remember drotation_drr01 is Tensor drotation_drr01[3][3] - // (3x3 rot) (3x3 components of rr01) + // (3x3 rot) (3x3 components of rr01) std::vector<Vector> v(n); Vector csum; // these below could probably be calculated in the main routine Vector cp; cp.zero(); if(!cpositions_is_removed)cp=cpositions; Vector cr; cr.zero(); if(!creference_is_removed)cr=creference; - for(unsigned iat=0;iat<n;iat++) csum+=(reference[iat]-cr)*align[iat]; - for(unsigned iat=0;iat<n;iat++) v[iat]=(reference[iat]-cr-csum)*align[iat]; - for(unsigned a=0;a<3;a++){ - for(unsigned b=0;b<3;b++){ - if(inverseTransform){ - DRotDPos[b][a].resize(n); - for(unsigned iat=0;iat<n;iat++){ - DRotDPos[b][a][iat]=matmul(drotation_drr01[a][b],v[iat]); - } - }else{ - DRotDPos[a][b].resize(n); - for(unsigned iat=0;iat<n;iat++){ - DRotDPos[a][b][iat]=matmul(drotation_drr01[a][b],v[iat]); - } - } - } + for(unsigned iat=0; iat<n; iat++) csum+=(reference[iat]-cr)*align[iat]; + for(unsigned iat=0; iat<n; iat++) v[iat]=(reference[iat]-cr-csum)*align[iat]; + for(unsigned a=0; a<3; a++) { + for(unsigned b=0; b<3; b++) { + if(inverseTransform) { + DRotDPos[b][a].resize(n); + for(unsigned iat=0; iat<n; iat++) { + DRotDPos[b][a][iat]=matmul(drotation_drr01[a][b],v[iat]); + } + } else { + DRotDPos[a][b].resize(n); + for(unsigned iat=0; iat<n; iat++) { + DRotDPos[a][b][iat]=matmul(drotation_drr01[a][b],v[iat]); + } + } + } } return DRotDPos; } @@ -1119,126 +1119,126 @@ respect to reference note that the this transformation overlap the reference onto position if inverseTransform=true then aligns the positions onto reference */ -Matrix<std::vector<Vector> > RMSDCoreData::getDRotationDReference( bool inverseTransform ){ +Matrix<std::vector<Vector> > RMSDCoreData::getDRotationDReference( bool inverseTransform ) { const unsigned n=static_cast<unsigned int>(reference.size()); plumed_massert(!retrieve_only_rotation,"You used only_rotation=true in doCoreCalc therefore you cannot retrieve this information now"); if(!isInitialized)plumed_merror("getDRotationDPositions to initialize the coreData first!"); - Matrix<std::vector<Vector> > DRotDRef=Matrix<std::vector<Vector> >(3,3); + Matrix<std::vector<Vector> > DRotDRef=Matrix<std::vector<Vector> >(3,3); // remember drotation_drr01 is Tensor drotation_drr01[3][3] - // (3x3 rot) (3x3 components of rr01) + // (3x3 rot) (3x3 components of rr01) std::vector<Vector> v(n); Vector csum; // these below could probably be calculated in the main routine Vector cp; cp.zero(); if(!cpositions_is_removed)cp=cpositions; Vector cr; cr.zero(); if(!creference_is_removed)cr=creference; - for(unsigned iat=0;iat<n;iat++) csum+=(positions[iat]-cp)*align[iat]; - for(unsigned iat=0;iat<n;iat++) v[iat]=(positions[iat]-cp-csum)*align[iat]; - - for(unsigned a=0;a<3;a++){ - for(unsigned b=0;b<3;b++){ - Tensor t_drotation_drr01=drotation_drr01[a][b].transpose(); - if(inverseTransform){ - DRotDRef[b][a].resize(n); - for(unsigned iat=0;iat<n;iat++){ - DRotDRef[b][a][iat]=matmul(t_drotation_drr01,v[iat]); - } - }else{ - DRotDRef[a][b].resize(n); - for(unsigned iat=0;iat<n;iat++){ - DRotDRef[a][b][iat]=matmul(t_drotation_drr01,v[iat]); - } - } - } + for(unsigned iat=0; iat<n; iat++) csum+=(positions[iat]-cp)*align[iat]; + for(unsigned iat=0; iat<n; iat++) v[iat]=(positions[iat]-cp-csum)*align[iat]; + + for(unsigned a=0; a<3; a++) { + for(unsigned b=0; b<3; b++) { + Tensor t_drotation_drr01=drotation_drr01[a][b].transpose(); + if(inverseTransform) { + DRotDRef[b][a].resize(n); + for(unsigned iat=0; iat<n; iat++) { + DRotDRef[b][a][iat]=matmul(t_drotation_drr01,v[iat]); + } + } else { + DRotDRef[a][b].resize(n); + for(unsigned iat=0; iat<n; iat++) { + DRotDRef[a][b][iat]=matmul(t_drotation_drr01,v[iat]); + } + } + } } return DRotDRef; } -std::vector<Vector> RMSDCoreData::getAlignedReferenceToPositions(){ - std::vector<Vector> alignedref; - const unsigned n=static_cast<unsigned int>(reference.size()); - alignedref.resize(n); - if(!isInitialized)plumed_merror("getAlignedReferenceToPostions needs to initialize the coreData first!"); - // avoid to calculate matrix element but use the sum of what you have - Vector cp; cp.zero(); if(!cpositions_is_removed)cp=cpositions; - for(unsigned iat=0;iat<n;iat++)alignedref[iat]=-d[iat]+positions[iat]-cp; - return alignedref; +std::vector<Vector> RMSDCoreData::getAlignedReferenceToPositions() { + std::vector<Vector> alignedref; + const unsigned n=static_cast<unsigned int>(reference.size()); + alignedref.resize(n); + if(!isInitialized)plumed_merror("getAlignedReferenceToPostions needs to initialize the coreData first!"); + // avoid to calculate matrix element but use the sum of what you have + Vector cp; cp.zero(); if(!cpositions_is_removed)cp=cpositions; + for(unsigned iat=0; iat<n; iat++)alignedref[iat]=-d[iat]+positions[iat]-cp; + return alignedref; } -std::vector<Vector> RMSDCoreData::getAlignedPositionsToReference(){ - std::vector<Vector> alignedpos; - if(!isInitialized)plumed_merror("getAlignedPostionsToReference needs to initialize the coreData first!"); - const unsigned n=static_cast<unsigned int>(positions.size()); - alignedpos.resize(n); - Vector cp; cp.zero(); if(!cpositions_is_removed)cp=cpositions; - // avoid to calculate matrix element but use the sum of what you have - for(unsigned iat=0;iat<n;iat++)alignedpos[iat]=matmul(rotation.transpose(),positions[iat]-cp); - return alignedpos; +std::vector<Vector> RMSDCoreData::getAlignedPositionsToReference() { + std::vector<Vector> alignedpos; + if(!isInitialized)plumed_merror("getAlignedPostionsToReference needs to initialize the coreData first!"); + const unsigned n=static_cast<unsigned int>(positions.size()); + alignedpos.resize(n); + Vector cp; cp.zero(); if(!cpositions_is_removed)cp=cpositions; + // avoid to calculate matrix element but use the sum of what you have + for(unsigned iat=0; iat<n; iat++)alignedpos[iat]=matmul(rotation.transpose(),positions[iat]-cp); + return alignedpos; } -std::vector<Vector> RMSDCoreData::getCenteredPositions(){ - std::vector<Vector> centeredpos; - const unsigned n=static_cast<unsigned int>(reference.size()); - centeredpos.resize(n); - if(!isInitialized)plumed_merror("getCenteredPositions needs to initialize the coreData first!"); - // avoid to calculate matrix element but use the sum of what you have - for(unsigned iat=0;iat<n;iat++)centeredpos[iat]=positions[iat]-cpositions; - return centeredpos; +std::vector<Vector> RMSDCoreData::getCenteredPositions() { + std::vector<Vector> centeredpos; + const unsigned n=static_cast<unsigned int>(reference.size()); + centeredpos.resize(n); + if(!isInitialized)plumed_merror("getCenteredPositions needs to initialize the coreData first!"); + // avoid to calculate matrix element but use the sum of what you have + for(unsigned iat=0; iat<n; iat++)centeredpos[iat]=positions[iat]-cpositions; + return centeredpos; } -std::vector<Vector> RMSDCoreData::getCenteredReference(){ - std::vector<Vector> centeredref; - const unsigned n=static_cast<unsigned int>(reference.size()); - centeredref.resize(n); - if(!isInitialized)plumed_merror("getCenteredReference needs to initialize the coreData first!"); - // avoid to calculate matrix element but use the sum of what you have - Vector cr; cr.zero(); if(!creference_is_removed)cr=creference; - for(unsigned iat=0;iat<n;iat++)centeredref[iat]=reference[iat]-cr; - return centeredref; +std::vector<Vector> RMSDCoreData::getCenteredReference() { + std::vector<Vector> centeredref; + const unsigned n=static_cast<unsigned int>(reference.size()); + centeredref.resize(n); + if(!isInitialized)plumed_merror("getCenteredReference needs to initialize the coreData first!"); + // avoid to calculate matrix element but use the sum of what you have + Vector cr; cr.zero(); if(!creference_is_removed)cr=creference; + for(unsigned iat=0; iat<n; iat++)centeredref[iat]=reference[iat]-cr; + return centeredref; } -Vector RMSDCoreData::getPositionsCenter(){ - if(!isInitialized)plumed_merror("getCenteredPositions needs to initialize the coreData first!"); - return cpositions; +Vector RMSDCoreData::getPositionsCenter() { + if(!isInitialized)plumed_merror("getCenteredPositions needs to initialize the coreData first!"); + return cpositions; } -Vector RMSDCoreData::getReferenceCenter(){ - if(!isInitialized)plumed_merror("getCenteredPositions needs to initialize the coreData first!"); - return creference; +Vector RMSDCoreData::getReferenceCenter() { + if(!isInitialized)plumed_merror("getCenteredPositions needs to initialize the coreData first!"); + return creference; } -Tensor RMSDCoreData::getRotationMatrixReferenceToPositions(){ - if(!isInitialized)plumed_merror("getRotationMatrixReferenceToPositions needs to initialize the coreData first!"); - return rotation; +Tensor RMSDCoreData::getRotationMatrixReferenceToPositions() { + if(!isInitialized)plumed_merror("getRotationMatrixReferenceToPositions needs to initialize the coreData first!"); + return rotation; } -Tensor RMSDCoreData::getRotationMatrixPositionsToReference(){ - if(!isInitialized)plumed_merror("getRotationMatrixReferenceToPositions needs to initialize the coreData first!"); - return rotation.transpose(); +Tensor RMSDCoreData::getRotationMatrixPositionsToReference() { + if(!isInitialized)plumed_merror("getRotationMatrixReferenceToPositions needs to initialize the coreData first!"); + return rotation.transpose(); } template double RMSD::optimalAlignment<true,true>(const std::vector<double> & align, - const std::vector<double> & displace, - const std::vector<Vector> & positions, - const std::vector<Vector> & reference , - std::vector<Vector> & derivatives, bool squared)const; + const std::vector<double> & displace, + const std::vector<Vector> & positions, + const std::vector<Vector> & reference, + std::vector<Vector> & derivatives, bool squared)const; template double RMSD::optimalAlignment<true,false>(const std::vector<double> & align, - const std::vector<double> & displace, - const std::vector<Vector> & positions, - const std::vector<Vector> & reference , - std::vector<Vector> & derivatives, bool squared)const; + const std::vector<double> & displace, + const std::vector<Vector> & positions, + const std::vector<Vector> & reference, + std::vector<Vector> & derivatives, bool squared)const; template double RMSD::optimalAlignment<false,true>(const std::vector<double> & align, - const std::vector<double> & displace, - const std::vector<Vector> & positions, - const std::vector<Vector> & reference , - std::vector<Vector> & derivatives, bool squared)const; + const std::vector<double> & displace, + const std::vector<Vector> & positions, + const std::vector<Vector> & reference, + std::vector<Vector> & derivatives, bool squared)const; template double RMSD::optimalAlignment<false,false>(const std::vector<double> & align, - const std::vector<double> & displace, - const std::vector<Vector> & positions, - const std::vector<Vector> & reference , - std::vector<Vector> & derivatives, bool squared)const; + const std::vector<double> & displace, + const std::vector<Vector> & positions, + const std::vector<Vector> & reference, + std::vector<Vector> & derivatives, bool squared)const; diff --git a/src/tools/RMSD.h b/src/tools/RMSD.h index 8e1a8851a..b7c80bfa4 100644 --- a/src/tools/RMSD.h +++ b/src/tools/RMSD.h @@ -28,17 +28,17 @@ #include <vector> #include <string> -namespace PLMD{ +namespace PLMD { class Log; class PDB; /** \ingroup TOOLBOX A class that implements RMSD calculations -This is a class that implements the various infrastructure to calculate the +This is a class that implements the various infrastructure to calculate the RMSD or MSD respect a given frame. It can be done through an optimal alignment scheme -as Kearsley or, more simply, by resetting the center of mass. -This is the class that decides this. A very simple use is +as Kearsley or, more simply, by resetting the center of mass. +This is the class that decides this. A very simple use is \verbatim #include "tools/PDB.h" #include "tools/RMSD.h" @@ -50,11 +50,11 @@ PDB pdb; pdb.read("file.pdb",true,1.0); string type; type.assign("OPTIMAL"); -// set the reference and the type +// set the reference and the type rmsd.set(pdb,type); // this calculates the rmsd and the derivatives vector<Vector> derivs; -double val; +double val; val=rmsd.calculate(getPositions(),derivs,true); \endverbatim @@ -70,39 +70,39 @@ class RMSD std::vector<double> align; // Weights for deviation std::vector<double> displace; -// Center for reference and flag for its calculation +// Center for reference and flag for its calculation Vector reference_center; bool reference_center_is_calculated; - bool reference_center_is_removed; + bool reference_center_is_removed; // Center for running position (not used in principle but here to reflect reference/positio symmetry Vector positions_center; - bool positions_center_is_calculated; - bool positions_center_is_removed; + bool positions_center_is_calculated; + bool positions_center_is_removed; // calculates the center from the position provided - Vector calculateCenter(std::vector<Vector> &p,std::vector<double> &w){ - plumed_massert(p.size()==w.size(),"mismatch in dimension of position/align arrays while calculating the center"); - unsigned n; n=p.size(); - Vector c; c.zero(); - for(unsigned i=0;i<n;i++)c+=p[i]*w[i]; - return c; + Vector calculateCenter(std::vector<Vector> &p,std::vector<double> &w) { + plumed_massert(p.size()==w.size(),"mismatch in dimension of position/align arrays while calculating the center"); + unsigned n; n=p.size(); + Vector c; c.zero(); + for(unsigned i=0; i<n; i++)c+=p[i]*w[i]; + return c; }; // removes the center for the position provided - void removeCenter(std::vector<Vector> &p, Vector &c){ - unsigned n; n=p.size(); - for(unsigned i=0;i<n;i++)p[i]-=c; + void removeCenter(std::vector<Vector> &p, Vector &c) { + unsigned n; n=p.size(); + for(unsigned i=0; i<n; i++)p[i]-=c; }; // add center - void addCenter(std::vector<Vector> &p, Vector &c){Vector cc=c*-1.;removeCenter(p,cc);}; + void addCenter(std::vector<Vector> &p, Vector &c) {Vector cc=c*-1.; removeCenter(p,cc);}; public: /// Constructor RMSD(); /// clear the structure void clear(); -/// set reference, align and displace from input pdb structure: evtl remove com from the initial structure and normalize the input weights from the pdb +/// set reference, align and displace from input pdb structure: evtl remove com from the initial structure and normalize the input weights from the pdb void set(const PDB&,const std::string & mytype, bool remove_center=true, bool normalize_weights=true); /// set align displace reference and type from input vectors - void set(const std::vector<double> & align, const std::vector<double> & displace, const std::vector<Vector> & reference ,const std::string & mytype, bool remove_center=true , bool normalize_weights=true ); + void set(const std::vector<double> & align, const std::vector<double> & displace, const std::vector<Vector> & reference,const std::string & mytype, bool remove_center=true, bool normalize_weights=true ); /// set the type of alignment we are doing void setType(const std::string & mytype); /// set reference coordinates, remove the com by using uniform weights @@ -111,215 +111,219 @@ public: void setAlign(const std::vector<double> & align, bool normalize_weights=true, bool remove_center=true); /// set align void setDisplace(const std::vector<double> & displace, bool normalize_weights=true); -/// - std::string getMethod(); +/// + std::string getMethod(); /// workhorses double simpleAlignment(const std::vector<double> & align, - const std::vector<double> & displace, - const std::vector<Vector> & positions, - const std::vector<Vector> & reference , - std::vector<Vector> & derivatives, - std::vector<Vector> & displacement, - bool squared=false)const; -template <bool safe,bool alEqDis> + const std::vector<double> & displace, + const std::vector<Vector> & positions, + const std::vector<Vector> & reference, + std::vector<Vector> & derivatives, + std::vector<Vector> & displacement, + bool squared=false)const; + template <bool safe,bool alEqDis> double optimalAlignment(const std::vector<double> & align, const std::vector<double> & displace, const std::vector<Vector> & positions, - const std::vector<Vector> & reference , + const std::vector<Vector> & reference, std::vector<Vector> & DDistDPos, bool squared=false)const; -template <bool safe,bool alEqDis> -double optimalAlignment_DDistDRef(const std::vector<double> & align, - const std::vector<double> & displace, - const std::vector<Vector> & positions, - const std::vector<Vector> & reference , - std::vector<Vector> & DDistDPos, - std::vector<Vector> & DDistDRef, - bool squared=false) const; + template <bool safe,bool alEqDis> + double optimalAlignment_DDistDRef(const std::vector<double> & align, + const std::vector<double> & displace, + const std::vector<Vector> & positions, + const std::vector<Vector> & reference, + std::vector<Vector> & DDistDPos, + std::vector<Vector> & DDistDRef, + bool squared=false) const; -template <bool safe,bool alEqDis> -double optimalAlignment_SOMA(const std::vector<double> & align, - const std::vector<double> & displace, - const std::vector<Vector> & positions, - const std::vector<Vector> & reference , - std::vector<Vector> & DDistDPos, - std::vector<Vector> & DDistDRef, - bool squared=false) const; + template <bool safe,bool alEqDis> + double optimalAlignment_SOMA(const std::vector<double> & align, + const std::vector<double> & displace, + const std::vector<Vector> & positions, + const std::vector<Vector> & reference, + std::vector<Vector> & DDistDPos, + std::vector<Vector> & DDistDRef, + bool squared=false) const; + + template <bool safe,bool alEqDis> + double optimalAlignment_DDistDRef_Rot_DRotDPos(const std::vector<double> & align, + const std::vector<double> & displace, + const std::vector<Vector> & positions, + const std::vector<Vector> & reference, + std::vector<Vector> & DDistDPos, + std::vector<Vector> & DDistDRef, + Tensor & Rotation, + Matrix<std::vector<Vector> > &DRotDPos, + bool squared=false) const; -template <bool safe,bool alEqDis> -double optimalAlignment_DDistDRef_Rot_DRotDPos(const std::vector<double> & align, + template <bool safe,bool alEqDis> + double optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef(const std::vector<double> & align, + const std::vector<double> & displace, + const std::vector<Vector> & positions, + const std::vector<Vector> & reference, + std::vector<Vector> & DDistDPos, + std::vector<Vector> & DDistDRef, + Tensor & Rotation, + Matrix<std::vector<Vector> > &DRotDPos, + Matrix<std::vector<Vector> > &DRotDRef, + bool squared=false) const; + + template <bool safe,bool alEqDis> + double optimalAlignment_PCA(const std::vector<double> & align, const std::vector<double> & displace, const std::vector<Vector> & positions, - const std::vector<Vector> & reference , - std::vector<Vector> & DDistDPos, - std::vector<Vector> & DDistDRef, - Tensor & Rotation, - Matrix<std::vector<Vector> > &DRotDPos, - bool squared=false) const; + const std::vector<Vector> & reference, + std::vector<Vector> & alignedpositions, + std::vector<Vector> & centeredpositions, + std::vector<Vector> & centeredreference, + Tensor & Rotation, + std::vector<Vector> & DDistDPos, + Matrix<std::vector<Vector> > & DRotDPos, + bool squared=false) const ; -template <bool safe,bool alEqDis> -double optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef(const std::vector<double> & align, + template <bool safe,bool alEqDis> + double optimalAlignment_Fit(const std::vector<double> & align, const std::vector<double> & displace, const std::vector<Vector> & positions, - const std::vector<Vector> & reference , - std::vector<Vector> & DDistDPos, - std::vector<Vector> & DDistDRef, - Tensor & Rotation, - Matrix<std::vector<Vector> > &DRotDPos, - Matrix<std::vector<Vector> > &DRotDRef, - bool squared=false) const; - -template <bool safe,bool alEqDis> -double optimalAlignment_PCA(const std::vector<double> & align, - const std::vector<double> & displace, - const std::vector<Vector> & positions, - const std::vector<Vector> & reference, - std::vector<Vector> & alignedpositions, - std::vector<Vector> & centeredpositions, - std::vector<Vector> & centeredreference, - Tensor & Rotation, - std::vector<Vector> & DDistDPos, - Matrix<std::vector<Vector> > & DRotDPos, - bool squared=false) const ; - -template <bool safe,bool alEqDis> -double optimalAlignment_Fit(const std::vector<double> & align, - const std::vector<double> & displace, - const std::vector<Vector> & positions, - const std::vector<Vector> & reference, - Tensor & Rotation, - Matrix<std::vector<Vector> > & DRotDPos, - std::vector<Vector> & centeredpositions, - Vector & center_positions, - bool squared=false); + const std::vector<Vector> & reference, + Tensor & Rotation, + Matrix<std::vector<Vector> > & DRotDPos, + std::vector<Vector> & centeredpositions, + Vector & center_positions, + bool squared=false); -/// Compute rmsd: note that this is an intermediate layer which is kept in order to evtl expand with more alignment types/user options to be called while keeping the workhorses separated +/// Compute rmsd: note that this is an intermediate layer which is kept in order to evtl expand with more alignment types/user options to be called while keeping the workhorses separated double calculate(const std::vector<Vector> & positions,std::vector<Vector> &derivatives, bool squared=false)const; /// Other convenience methods: -/// calculate the derivative of distance respect to position(DDistDPos) and reference (DDistDPos) - double calc_DDistDRef( const std::vector<Vector>& positions, std::vector<Vector> &DDistDPos, std::vector<Vector>& DDistDRef , const bool squared=false ); +/// calculate the derivative of distance respect to position(DDistDPos) and reference (DDistDPos) + double calc_DDistDRef( const std::vector<Vector>& positions, std::vector<Vector> &DDistDPos, std::vector<Vector>& DDistDRef, const bool squared=false ); /// calculate the derivative for SOMA (i.e. derivative respect to reference frame without the matrix derivative) - double calc_SOMA( const std::vector<Vector>& positions, std::vector<Vector> &DDistDPos, std::vector<Vector>& DDistDRef , const bool squared=false ); + double calc_SOMA( const std::vector<Vector>& positions, std::vector<Vector> &DDistDPos, std::vector<Vector>& DDistDRef, const bool squared=false ); /// - double calc_DDistDRef_Rot_DRotDPos( const std::vector<Vector>& positions, std::vector<Vector> &DDistDPos, std::vector<Vector>& DDistDRef , Tensor & Rotation,Matrix<std::vector<Vector> > &DRotDPos, const bool squared=false ); - double calc_DDistDRef_Rot_DRotDPos_DRotDRef( const std::vector<Vector>& positions, std::vector<Vector> &DDistDPos, std::vector<Vector>& DDistDRef , Tensor & Rotation,Matrix<std::vector<Vector> > &DRotDPos,Matrix<std::vector<Vector> > &DRotDRef, const bool squared=false ); - /// convenience method to retrieve all the bits and pieces for PCA - double calc_PCAelements( const std::vector<Vector>& pos, std::vector<Vector> &DDistDPos, Tensor & Rotation, Matrix<std::vector<Vector> > & DRotDPos,std::vector<Vector> & alignedpositions, std::vector<Vector> & centeredpositions, std::vector<Vector> ¢eredreference, const bool& squared=false) const ; - /// convenience method to retrieve all the bits and pieces needed by FitToTemplate - double calc_FitElements( const std::vector<Vector>& pos, Tensor & Rotation, Matrix<std::vector<Vector> > & DRotDPos,std::vector<Vector> & centeredpositions ,Vector & center_positions, const bool& squared=false ); - /// static convenience method to get the matrix i,a from drotdpos (which is a bit tricky) - static Tensor getMatrixFromDRot(Matrix< std::vector<Vector> > &drotdpos, const unsigned &i, const unsigned &a){ - Tensor t; - t[0][0]=drotdpos[0][0][i][a]; t[0][1]=drotdpos[0][1][i][a]; t[0][2]=drotdpos[0][2][i][a]; - t[1][0]=drotdpos[1][0][i][a]; t[1][1]=drotdpos[1][1][i][a]; t[1][2]=drotdpos[1][2][i][a]; - t[2][0]=drotdpos[2][0][i][a]; t[2][1]=drotdpos[2][1][i][a]; t[2][2]=drotdpos[2][2][i][a]; - return t; - }; + double calc_DDistDRef_Rot_DRotDPos( const std::vector<Vector>& positions, std::vector<Vector> &DDistDPos, std::vector<Vector>& DDistDRef, Tensor & Rotation,Matrix<std::vector<Vector> > &DRotDPos, const bool squared=false ); + double calc_DDistDRef_Rot_DRotDPos_DRotDRef( const std::vector<Vector>& positions, std::vector<Vector> &DDistDPos, std::vector<Vector>& DDistDRef, Tensor & Rotation,Matrix<std::vector<Vector> > &DRotDPos,Matrix<std::vector<Vector> > &DRotDRef, const bool squared=false ); +/// convenience method to retrieve all the bits and pieces for PCA + double calc_PCAelements( const std::vector<Vector>& pos, std::vector<Vector> &DDistDPos, Tensor & Rotation, Matrix<std::vector<Vector> > & DRotDPos,std::vector<Vector> & alignedpositions, std::vector<Vector> & centeredpositions, std::vector<Vector> ¢eredreference, const bool& squared=false) const ; +/// convenience method to retrieve all the bits and pieces needed by FitToTemplate + double calc_FitElements( const std::vector<Vector>& pos, Tensor & Rotation, Matrix<std::vector<Vector> > & DRotDPos,std::vector<Vector> & centeredpositions,Vector & center_positions, const bool& squared=false ); +/// static convenience method to get the matrix i,a from drotdpos (which is a bit tricky) + static Tensor getMatrixFromDRot(Matrix< std::vector<Vector> > &drotdpos, const unsigned &i, const unsigned &a) { + Tensor t; + t[0][0]=drotdpos[0][0][i][a]; t[0][1]=drotdpos[0][1][i][a]; t[0][2]=drotdpos[0][2][i][a]; + t[1][0]=drotdpos[1][0][i][a]; t[1][1]=drotdpos[1][1][i][a]; t[1][2]=drotdpos[1][2][i][a]; + t[2][0]=drotdpos[2][0][i][a]; t[2][1]=drotdpos[2][1][i][a]; t[2][2]=drotdpos[2][2][i][a]; + return t; + }; }; /// this is a class which is needed to share information across the various non-threadsafe routines -/// so that the public function of rmsd are threadsafe while the inner core can safely share information +/// so that the public function of rmsd are threadsafe while the inner core can safely share information class RMSDCoreData { - private: - bool alEqDis; - bool distanceIsMSD; // default is RMSD but can deliver the MSD - bool hasDistance; // distance is already calculated - bool isInitialized; - bool safe; +private: + bool alEqDis; + bool distanceIsMSD; // default is RMSD but can deliver the MSD + bool hasDistance; // distance is already calculated + bool isInitialized; + bool safe; - // this need to be copied and they are small, should not affect the performance - Vector creference; - bool creference_is_calculated; - bool creference_is_removed; - Vector cpositions; - bool cpositions_is_calculated; - bool cpositions_is_removed; - bool retrieve_only_rotation; + // this need to be copied and they are small, should not affect the performance + Vector creference; + bool creference_is_calculated; + bool creference_is_removed; + Vector cpositions; + bool cpositions_is_calculated; + bool cpositions_is_removed; + bool retrieve_only_rotation; - // use reference assignment to speed up instead of copying - const std::vector<Vector> &positions; - const std::vector<Vector> &reference; - const std::vector<double> &align; - const std::vector<double> &displace; + // use reference assignment to speed up instead of copying + const std::vector<Vector> &positions; + const std::vector<Vector> &reference; + const std::vector<double> &align; + const std::vector<double> &displace; - // the needed stuff for distance and more (one could use eigenvecs components and eigenvals for some reason) - double dist; - std::vector<double> eigenvals; - Matrix<double> eigenvecs; - double rr00; // sum of positions squared (needed for dist calc) - double rr11; // sum of reference squared (needed for dist calc) - Tensor rotation; // rotation derived from the eigenvector having the smallest eigenvalue - Tensor drotation_drr01[3][3]; // derivative of the rotation only available when align!=displace - Tensor ddist_drr01; - Tensor ddist_drotation; - std::vector<Vector> d; // difference of components - public: - /// the constructor (note: only references are passed, therefore is rather fast) - /// note: this aligns the reference onto the positions - /// - /// this method assumes that the centers are already calculated and subtracted - RMSDCoreData(const std::vector<double> &a ,const std::vector<double> &d,const std::vector<Vector> &p, const std::vector<Vector> &r, Vector &cp, Vector &cr ): - alEqDis(false),distanceIsMSD(false),hasDistance(false),isInitialized(false),safe(false), - creference(cr),creference_is_calculated(true),creference_is_removed(true), - cpositions(cp),cpositions_is_calculated(true),cpositions_is_removed(true),retrieve_only_rotation(false),positions(p),reference(r),align(a),displace(d),dist(0.0),rr00(0.0),rr11(0.0){}; + // the needed stuff for distance and more (one could use eigenvecs components and eigenvals for some reason) + double dist; + std::vector<double> eigenvals; + Matrix<double> eigenvecs; + double rr00; // sum of positions squared (needed for dist calc) + double rr11; // sum of reference squared (needed for dist calc) + Tensor rotation; // rotation derived from the eigenvector having the smallest eigenvalue + Tensor drotation_drr01[3][3]; // derivative of the rotation only available when align!=displace + Tensor ddist_drr01; + Tensor ddist_drotation; + std::vector<Vector> d; // difference of components +public: + /// the constructor (note: only references are passed, therefore is rather fast) + /// note: this aligns the reference onto the positions + /// + /// this method assumes that the centers are already calculated and subtracted + RMSDCoreData(const std::vector<double> &a,const std::vector<double> &d,const std::vector<Vector> &p, const std::vector<Vector> &r, Vector &cp, Vector &cr ): + alEqDis(false),distanceIsMSD(false),hasDistance(false),isInitialized(false),safe(false), + creference(cr),creference_is_calculated(true),creference_is_removed(true), + cpositions(cp),cpositions_is_calculated(true),cpositions_is_removed(true),retrieve_only_rotation(false),positions(p),reference(r),align(a),displace(d),dist(0.0),rr00(0.0),rr11(0.0) {}; - // this constructor does not assume that the positions and reference have the center subtracted - RMSDCoreData(const std::vector<double> &a ,const std::vector<double> &d,const std::vector<Vector> &p, const std::vector<Vector> &r): - alEqDis(false),distanceIsMSD(false),hasDistance(false),isInitialized(false),safe(false), - creference_is_calculated(false),creference_is_removed(false), - cpositions_is_calculated(false),cpositions_is_removed(false),retrieve_only_rotation(false),positions(p),reference(r),align(a),displace(d),dist(0.0),rr00(0.0),rr11(0.0) - {cpositions.zero();creference.zero();}; + // this constructor does not assume that the positions and reference have the center subtracted + RMSDCoreData(const std::vector<double> &a,const std::vector<double> &d,const std::vector<Vector> &p, const std::vector<Vector> &r): + alEqDis(false),distanceIsMSD(false),hasDistance(false),isInitialized(false),safe(false), + creference_is_calculated(false),creference_is_removed(false), + cpositions_is_calculated(false),cpositions_is_removed(false),retrieve_only_rotation(false),positions(p),reference(r),align(a),displace(d),dist(0.0),rr00(0.0),rr11(0.0) + {cpositions.zero(); creference.zero();}; - // set the center on the fly without subtracting - void calcPositionsCenter(){plumed_massert(!cpositions_is_calculated,"the center was already calculated"); - cpositions.zero();for(unsigned i=0;i<positions.size();i++){cpositions+=positions[i]*align[i];}cpositions_is_calculated=true;} - void calcReferenceCenter(){plumed_massert(!creference_is_calculated,"the center was already calculated"); - creference.zero();for(unsigned i=0;i<reference.size();i++){creference+=reference[i]*align[i];}creference_is_calculated=true;}; - // assume the center is given externally - void setPositionsCenter(Vector v){plumed_massert(!cpositions_is_calculated,"You are setting the center two times!");cpositions=v;cpositions_is_calculated=true;}; - void setReferenceCenter(Vector v){plumed_massert(!creference_is_calculated,"You are setting the center two times!");creference=v;creference_is_calculated=true;}; - // the center is already removed - void setPositionsCenterIsRemoved(bool t){cpositions_is_removed=t;}; - void setReferenceCenterIsRemoved(bool t){creference_is_removed=t;}; - bool getPositionsCenterIsRemoved(){return cpositions_is_removed;}; - bool getReferenceCenterIsRemoved(){return creference_is_removed;}; - // does the core calc : first thing to call after the constructor: - // only_rotation=true does not retrieve the derivatives, just retrieve the optimal rotation (the same calc cannot be exploit further) - void doCoreCalc(bool safe,bool alEqDis, bool only_rotation=false); - // retrieve the distance if required after doCoreCalc - double getDistance(bool squared); - // retrieve the derivative of the distance respect to the position - std::vector<Vector> getDDistanceDPositions(); - // retrieve the derivative of the distance respect to the reference - std::vector<Vector> getDDistanceDReference(); - // specific version for SOMA calculation (i.e. does not need derivative respect to rotation matrix) - std::vector<Vector> getDDistanceDReferenceSOMA(); - // get aligned reference onto position - std::vector<Vector> getAlignedReferenceToPositions(); - // get aligned position onto reference - std::vector<Vector> getAlignedPositionsToReference(); - // get centered positions - std::vector<Vector> getCenteredPositions(); - // get centered reference - std::vector<Vector> getCenteredReference(); - // get center of positions - Vector getPositionsCenter(); - // get center of reference - Vector getReferenceCenter(); - // get rotation matrix (reference ->positions) - Tensor getRotationMatrixReferenceToPositions(); - // get rotation matrix (positions -> reference) - Tensor getRotationMatrixPositionsToReference(); - // get the derivative of the rotation matrix respect to positions - // note that the this transformation overlap the reference onto position - // if inverseTransform=true then aligns the positions onto reference - Matrix<std::vector<Vector> > getDRotationDPositions( bool inverseTransform=false ); - // get the derivative of the rotation matrix respect to reference - // note that the this transformation overlap the reference onto position - // if inverseTransform=true then aligns the positions onto reference - Matrix<std::vector<Vector> > getDRotationDReference(bool inverseTransform=false ); + // set the center on the fly without subtracting + void calcPositionsCenter() { + plumed_massert(!cpositions_is_calculated,"the center was already calculated"); + cpositions.zero(); for(unsigned i=0; i<positions.size(); i++) {cpositions+=positions[i]*align[i];} cpositions_is_calculated=true; + } + void calcReferenceCenter() { + plumed_massert(!creference_is_calculated,"the center was already calculated"); + creference.zero(); for(unsigned i=0; i<reference.size(); i++) {creference+=reference[i]*align[i];} creference_is_calculated=true; + }; + // assume the center is given externally + void setPositionsCenter(Vector v) {plumed_massert(!cpositions_is_calculated,"You are setting the center two times!"); cpositions=v; cpositions_is_calculated=true;}; + void setReferenceCenter(Vector v) {plumed_massert(!creference_is_calculated,"You are setting the center two times!"); creference=v; creference_is_calculated=true;}; + // the center is already removed + void setPositionsCenterIsRemoved(bool t) {cpositions_is_removed=t;}; + void setReferenceCenterIsRemoved(bool t) {creference_is_removed=t;}; + bool getPositionsCenterIsRemoved() {return cpositions_is_removed;}; + bool getReferenceCenterIsRemoved() {return creference_is_removed;}; + // does the core calc : first thing to call after the constructor: + // only_rotation=true does not retrieve the derivatives, just retrieve the optimal rotation (the same calc cannot be exploit further) + void doCoreCalc(bool safe,bool alEqDis, bool only_rotation=false); + // retrieve the distance if required after doCoreCalc + double getDistance(bool squared); + // retrieve the derivative of the distance respect to the position + std::vector<Vector> getDDistanceDPositions(); + // retrieve the derivative of the distance respect to the reference + std::vector<Vector> getDDistanceDReference(); + // specific version for SOMA calculation (i.e. does not need derivative respect to rotation matrix) + std::vector<Vector> getDDistanceDReferenceSOMA(); + // get aligned reference onto position + std::vector<Vector> getAlignedReferenceToPositions(); + // get aligned position onto reference + std::vector<Vector> getAlignedPositionsToReference(); + // get centered positions + std::vector<Vector> getCenteredPositions(); + // get centered reference + std::vector<Vector> getCenteredReference(); + // get center of positions + Vector getPositionsCenter(); + // get center of reference + Vector getReferenceCenter(); + // get rotation matrix (reference ->positions) + Tensor getRotationMatrixReferenceToPositions(); + // get rotation matrix (positions -> reference) + Tensor getRotationMatrixPositionsToReference(); + // get the derivative of the rotation matrix respect to positions + // note that the this transformation overlap the reference onto position + // if inverseTransform=true then aligns the positions onto reference + Matrix<std::vector<Vector> > getDRotationDPositions( bool inverseTransform=false ); + // get the derivative of the rotation matrix respect to reference + // note that the this transformation overlap the reference onto position + // if inverseTransform=true then aligns the positions onto reference + Matrix<std::vector<Vector> > getDRotationDReference(bool inverseTransform=false ); }; } diff --git a/src/tools/Random.cpp b/src/tools/Random.cpp index 8d5cac5d2..7d03b9da3 100644 --- a/src/tools/Random.cpp +++ b/src/tools/Random.cpp @@ -25,7 +25,7 @@ #include <sstream> #include <iostream> -namespace PLMD{ +namespace PLMD { const double Random::fact=5.9604644775390625e-8; /* 1 / 2^24 */ const double Random::EPS=3.0e-16; @@ -43,92 +43,92 @@ Random::Random(const std::string & name): // static constructors. name(&name!=&noname?name:"noname") { - iy=0; - iv[0]=0; - setSeed(0); + iy=0; + iv[0]=0; + setSeed(0); } -void Random::setSeed(int idum_){ - idum=idum_; - incPrec=false; +void Random::setSeed(int idum_) { + idum=idum_; + incPrec=false; } double Random::RandU01 () { - if (incPrec) - return U01d(); - else - return U01(); + if (incPrec) + return U01d(); + else + return U01(); } double Random::U01d () { - double u; - u = U01(); - u += U01() * fact; - return (u < 1.0) ? u : (u - 1.0); + double u; + u = U01(); + u += U01() * fact; + return (u < 1.0) ? u : (u - 1.0); } -double Random::U01(){ - int j,k; - double temp; - if (idum <= 0 || !iy) { - if (-idum < 1) idum=1; - else idum = -idum; - for (j=NTAB+7;j>=0;j--) { - k=idum/IQ; - idum=IA*(idum-k*IQ)-IR*k; - if (idum < 0) idum += IM; - if (j < NTAB) iv[j] = idum; - } - iy=iv[0]; - } - k=idum/IQ; - idum=IA*(idum-k*IQ)-IR*k; - if (idum < 0) idum += IM; - j=iy/NDIV; - iy=iv[j]; - iv[j] = idum; - if ((temp=AM*iy) > RNMX) return RNMX; - else return temp; +double Random::U01() { + int j,k; + double temp; + if (idum <= 0 || !iy) { + if (-idum < 1) idum=1; + else idum = -idum; + for (j=NTAB+7; j>=0; j--) { + k=idum/IQ; + idum=IA*(idum-k*IQ)-IR*k; + if (idum < 0) idum += IM; + if (j < NTAB) iv[j] = idum; + } + iy=iv[0]; + } + k=idum/IQ; + idum=IA*(idum-k*IQ)-IR*k; + if (idum < 0) idum += IM; + j=iy/NDIV; + iy=iv[j]; + iv[j] = idum; + if ((temp=AM*iy) > RNMX) return RNMX; + else return temp; } -void Random::WriteStateFull(std::ostream & out)const{ - out<<name<<std::endl; - out<<idum<<" "<<iy; - for(int i=0;i<NTAB;i++){ - out<<" "<<iv[i]; - }; - out<<" "<<switchGaussian; - out<<" "<<saveGaussian; - out<<std::endl; +void Random::WriteStateFull(std::ostream & out)const { + out<<name<<std::endl; + out<<idum<<" "<<iy; + for(int i=0; i<NTAB; i++) { + out<<" "<<iv[i]; + }; + out<<" "<<switchGaussian; + out<<" "<<saveGaussian; + out<<std::endl; } -void Random::ReadStateFull (std::istream & in){ - getline(in,name); - in>>idum>>iy; - for (int i = 0; i < NTAB; i++) in>>iv[i]; - in>>switchGaussian; - in>>saveGaussian; +void Random::ReadStateFull (std::istream & in) { + getline(in,name); + in>>idum>>iy; + for (int i = 0; i < NTAB; i++) in>>iv[i]; + in>>switchGaussian; + in>>saveGaussian; } -void Random::toString(std::string & str)const{ - std::ostringstream ostr; - ostr<<idum<<"|"<<iy; - for(int i=0;i<NTAB;i++){ - ostr<<"|"<<iv[i]; - }; - str=ostr.str(); +void Random::toString(std::string & str)const { + std::ostringstream ostr; + ostr<<idum<<"|"<<iy; + for(int i=0; i<NTAB; i++) { + ostr<<"|"<<iv[i]; + }; + str=ostr.str(); } -void Random::fromString(const std::string & str){ - std::string s=str; - for(unsigned i=0;i<s.length();i++) if(s[i]=='|') s[i]=' '; - std::istringstream istr(s.c_str()); - istr>>idum>>iy; - for (int i = 0; i < NTAB; i++) istr>>iv[i]; +void Random::fromString(const std::string & str) { + std::string s=str; + for(unsigned i=0; i<s.length(); i++) if(s[i]=='|') s[i]=' '; + std::istringstream istr(s.c_str()); + istr>>idum>>iy; + for (int i = 0; i < NTAB; i++) istr>>iv[i]; } // This allows to have the same stream of random numbers @@ -137,22 +137,22 @@ void Random::fromString(const std::string & str){ #pragma intel optimization_level 0 #endif -double Random::Gaussian(){ - double v1,v2,rsq; - if(switchGaussian){ - switchGaussian=false; - return saveGaussian; - } - while(true){ - v1=2.0*RandU01()-1.0; - v2=2.0*RandU01()-1.0; - rsq=v1*v1+v2*v2; - if(rsq<1.0 && rsq>0.0) break; - } - double fac=sqrt(-2.*std::log(rsq)/rsq); - saveGaussian=v1*fac; - switchGaussian=true; - return v2*fac; +double Random::Gaussian() { + double v1,v2,rsq; + if(switchGaussian) { + switchGaussian=false; + return saveGaussian; + } + while(true) { + v1=2.0*RandU01()-1.0; + v2=2.0*RandU01()-1.0; + rsq=v1*v1+v2*v2; + if(rsq<1.0 && rsq>0.0) break; + } + double fac=sqrt(-2.*std::log(rsq)/rsq); + saveGaussian=v1*fac; + switchGaussian=true; + return v2*fac; } } diff --git a/src/tools/Random.h b/src/tools/Random.h index 043b3bfe9..49e7a3b44 100644 --- a/src/tools/Random.h +++ b/src/tools/Random.h @@ -25,42 +25,42 @@ #include <string> #include <iosfwd> -namespace PLMD{ +namespace PLMD { /// \ingroup TOOLBOX -class Random{ - static const int IA=16807,IM=2147483647,IQ=127773,IR=2836,NTAB=32; - static const int NDIV=(1+(IM-1)/NTAB); - static const double EPS; - static const double AM; - static const double RNMX; - static const double fact; - static const std::string noname; - bool incPrec; - bool switchGaussian; - double saveGaussian; - int iy; - int iv[NTAB]; - int idum; - std::string name; +class Random { + static const int IA=16807,IM=2147483647,IQ=127773,IR=2836,NTAB=32; + static const int NDIV=(1+(IM-1)/NTAB); + static const double EPS; + static const double AM; + static const double RNMX; + static const double fact; + static const std::string noname; + bool incPrec; + bool switchGaussian; + double saveGaussian; + int iy; + int iv[NTAB]; + int idum; + std::string name; public: - explicit Random(const std::string & name=noname); - void setSeed(int idum); - double RandU01(); - double U01(); - double U01d(); - void WriteStateFull(std::ostream &)const; - void ReadStateFull (std::istream &); - void fromString(const std::string & str); - void toString(std::string & str)const; - friend std::ostream & operator<<(std::ostream & out,const Random & rng){ - rng.WriteStateFull(out); return out; - } - friend std::istream & operator>>(std::istream & in,Random & rng){ - rng.ReadStateFull(in); return in; - } - double Gaussian(); - void IncreasedPrecis(bool i){incPrec=i;} + explicit Random(const std::string & name=noname); + void setSeed(int idum); + double RandU01(); + double U01(); + double U01d(); + void WriteStateFull(std::ostream &)const; + void ReadStateFull (std::istream &); + void fromString(const std::string & str); + void toString(std::string & str)const; + friend std::ostream & operator<<(std::ostream & out,const Random & rng) { + rng.WriteStateFull(out); return out; + } + friend std::istream & operator>>(std::istream & in,Random & rng) { + rng.ReadStateFull(in); return in; + } + double Gaussian(); + void IncreasedPrecis(bool i) {incPrec=i;} }; } diff --git a/src/tools/RootFindingBase.h b/src/tools/RootFindingBase.h index 5f125a7c1..b73745560 100644 --- a/src/tools/RootFindingBase.h +++ b/src/tools/RootFindingBase.h @@ -54,20 +54,20 @@ void RootFindingBase<FCLASS>::doSearch( const std::vector<double>& dir, std::vec double ax=0.0, xx=1.0; bb.bracket( ax, xx, &F1dim<FCLASS>::getEng ); double xmin=bb.search( &F1dim<FCLASS>::getEng ); - for(unsigned i=0;i<p.size();++i) p[i] += xmin*dir[i]; + for(unsigned i=0; i<p.size(); ++i) p[i] += xmin*dir[i]; } template <class FCLASS> void RootFindingBase<FCLASS>::linesearch( const std::vector<double>& dir, std::vector<double>& p, engf_pointer myfunc ) const { - // Construct the object that turns points on a line into vectors + // Construct the object that turns points on a line into vectors F1dim<FCLASS> f1dim( p, dir, myclass_func, myfunc, NULL ); // Actually do the search - doSearch( dir, p, f1dim ); + doSearch( dir, p, f1dim ); } template <class FCLASS> void RootFindingBase<FCLASS>::lsearch( const std::vector<double>& dir, std::vector<double>& p, engfnc_pointer myfunc ) const { - // Construct the object that turns points on a line into vectors + // Construct the object that turns points on a line into vectors F1dim<FCLASS> f1dim( p, dir, myclass_func, NULL, myfunc ); // Actually do the search doSearch( dir, p, f1dim ); diff --git a/src/tools/Stopwatch.cpp b/src/tools/Stopwatch.cpp index c0d93e0e1..4393a7544 100644 --- a/src/tools/Stopwatch.cpp +++ b/src/tools/Stopwatch.cpp @@ -30,52 +30,52 @@ using namespace std; -namespace PLMD{ +namespace PLMD { // this is needed for friend operators -std::ostream& operator<<(std::ostream&os,const Stopwatch&sw){ +std::ostream& operator<<(std::ostream&os,const Stopwatch&sw) { return sw.log(os); } -void Stopwatch::Watch::start(){ +void Stopwatch::Watch::start() { running++; lastStart=std::chrono::high_resolution_clock::now(); } -void Stopwatch::Watch::stop(){ +void Stopwatch::Watch::stop() { pause(); cycles++; total+=lap; if(lap>max)max=lap; if(min>lap || cycles==1)min=lap; lap=0; -} +} -void Stopwatch::Watch::pause(){ +void Stopwatch::Watch::pause() { plumed_assert(running>0); running--; if(running!=0) return; auto t=std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now()-lastStart); lap+=t.count(); -} +} -void Stopwatch::start(const std::string & name){ +void Stopwatch::start(const std::string & name) { watches[name].start(); } -void Stopwatch::stop(const std::string & name){ +void Stopwatch::stop(const std::string & name) { watches[name].stop(); } -void Stopwatch::pause(const std::string & name){ +void Stopwatch::pause(const std::string & name) { watches[name].pause(); } -std::ostream& Stopwatch::log(std::ostream&os)const{ +std::ostream& Stopwatch::log(std::ostream&os)const { char buffer[1000]; buffer[0]=0; - for(unsigned i=0;i<40;i++) os<<" "; + for(unsigned i=0; i<40; i++) os<<" "; os<<" Cycles Total Average Minumum Maximum\n"; std::vector<std::string> names; @@ -84,10 +84,10 @@ std::ostream& Stopwatch::log(std::ostream&os)const{ const double frac=1.0/1000000000.0; - for(const auto & name : names){ + for(const auto & name : names) { const Watch&t(watches.find(name)->second); os<<name; - for(unsigned i=name.length();i<40;i++) os<<" "; + for(unsigned i=name.length(); i<40; i++) os<<" "; std::sprintf(buffer,"%12u %12.6f %12.6f %12.6f %12.6f\n", t.cycles, frac*t.total, frac*t.total/t.cycles, frac*t.min,frac*t.max); os<<buffer; } diff --git a/src/tools/Stopwatch.h b/src/tools/Stopwatch.h index 639412001..276a4a840 100644 --- a/src/tools/Stopwatch.h +++ b/src/tools/Stopwatch.h @@ -27,7 +27,7 @@ #include <iosfwd> #include <chrono> -namespace PLMD{ +namespace PLMD { /** \ingroup TOOLBOX @@ -96,10 +96,10 @@ int main(){ */ -class Stopwatch{ +class Stopwatch { /// Class to store a single stopwatch. /// Class Stopwatch contains a collection of them - class Watch{ + class Watch { public: std::chrono::time_point<std::chrono::high_resolution_clock> lastStart; long long int total = 0; @@ -129,17 +129,17 @@ public: }; inline -void Stopwatch::start(){ +void Stopwatch::start() { start(""); } inline -void Stopwatch::stop(){ +void Stopwatch::stop() { stop(""); } inline -void Stopwatch::pause(){ +void Stopwatch::pause() { pause(""); } diff --git a/src/tools/SwitchingFunction.cpp b/src/tools/SwitchingFunction.cpp index fa685d1b0..fcbe3bb37 100644 --- a/src/tools/SwitchingFunction.cpp +++ b/src/tools/SwitchingFunction.cpp @@ -30,9 +30,9 @@ #endif using namespace std; -namespace PLMD{ +namespace PLMD { -//+PLUMEDOC INTERNAL switchingfunction +//+PLUMEDOC INTERNAL switchingfunction /* Functions that measure whether values are less than a certain quantity. @@ -40,24 +40,24 @@ Switching functions \f$s(r)\f$ take a minimum of one input parameter \f$d_0\f$. For \f$r \le d_0 \quad s(r)=1.0\f$ while for \f$r > d_0\f$ the function decays smoothly to 0. The various switching functions available in plumed differ in terms of how this decay is performed. -Where there is an accepted convention in the literature (e.g. \ref COORDINATION) on the form of the +Where there is an accepted convention in the literature (e.g. \ref COORDINATION) on the form of the switching function we use the convention as the default. However, the flexibility to use different -switching functions is always present generally through a single keyword. This keyword generally +switching functions is always present generally through a single keyword. This keyword generally takes an input with the following form: \verbatim KEYWORD={TYPE <list of parameters>} -\endverbatim +\endverbatim The following table contains a list of the various switching functions that are available in plumed 2 together with an example input. <table align=center frame=void width=95%% cellpadding=5%%> -<tr> +<tr> <td> TYPE </td> <td> FUNCTION </td> <td> EXAMPLE INPUT </td> <td> DEFAULT PARAMETERS </td> </tr> <tr> <td>RATIONAL </td> <td> \f$ -s(r)=\frac{ 1 - \left(\frac{ r - d_0 }{ r_0 }\right)^{n} }{ 1 - \left(\frac{ r - d_0 }{ r_0 }\right)^{m} } +s(r)=\frac{ 1 - \left(\frac{ r - d_0 }{ r_0 }\right)^{n} }{ 1 - \left(\frac{ r - d_0 }{ r_0 }\right)^{m} } \f$ </td> <td> {RATIONAL R_0=\f$r_0\f$ D_0=\f$d_0\f$ NN=\f$n\f$ MM=\f$m\f$} @@ -67,7 +67,7 @@ s(r)=\frac{ 1 - \left(\frac{ r - d_0 }{ r_0 }\right)^{n} }{ 1 - \left(\frac{ r - \f$ s(r)=\exp\left(-\frac{ r - d_0 }{ r_0 }\right) \f$ -</td> <td> +</td> <td> {EXP R_0=\f$r_0\f$ D_0=\f$d_0\f$} </td> <td> \f$d_0=0.0\f$ </td> </tr> <tr> @@ -76,9 +76,9 @@ s(r)=\exp\left(-\frac{ r - d_0 }{ r_0 }\right) s(r)=\exp\left(-\frac{ (r - d_0)^2 }{ 2r_0^2 }\right) \f$ </td> <td> -{GAUSSIAN R_0=\f$r_0\f$ D_0=\f$d_0\f$} +{GAUSSIAN R_0=\f$r_0\f$ D_0=\f$d_0\f$} </td> <td> \f$d_0=0.0\f$ </td> -</tr> <tr> +</tr> <tr> <td> SMAP </td> <td> \f$ s(r) = \left[ 1 + ( 2^{a/b} -1 )\left( \frac{r-d_0}{r_0} \right)^a \right]^{-b/a} @@ -86,7 +86,7 @@ s(r) = \left[ 1 + ( 2^{a/b} -1 )\left( \frac{r-d_0}{r_0} \right)^a \right]^{-b/a </td> <td> {SMAP R_0=\f$r_0\f$ D_0=\f$d_0\f$ A=\f$a\f$ B=\f$b\f$} </td> <td> \f$d_0=0.0\f$ </td> -</tr> <tr> +</tr> <tr> <td> Q </td> <td> \f$ s(r) = \frac{1}{1 + \exp(\beta(r_{ij} - \lambda r_{ij}^0))} @@ -94,7 +94,7 @@ s(r) = \frac{1}{1 + \exp(\beta(r_{ij} - \lambda r_{ij}^0))} </td> <td> {Q REF=\f$r_{ij}^0\f$ BETA=\f$\beta\f$ LAMBDA=\f$\lambda\f$ } </td> <td> \f$\lambda=1.8\f$, \f$\beta=50 nm^-1\f$ (all-atom)<br/>\f$\lambda=1.5\f$, \f$\beta=50 nm^-1\f$ (coarse-grained) </td> -</tr> <tr> +</tr> <tr> <td> CUBIC </td> <td> \f$ s(r) = (y-1)^2(1+2y) \qquad \textrm{where} \quad y = \frac{r - r_1}{r_0-r_1} @@ -102,15 +102,15 @@ s(r) = (y-1)^2(1+2y) \qquad \textrm{where} \quad y = \frac{r - r_1}{r_0-r_1} </td> <td> {CUBIC D_0=\f$r_1\f$ D_MAX=\f$r_0\f$} </td> <td> </td> -</tr> <tr> +</tr> <tr> <td> TANH </td> <td> \f$ -s(r) = 1 - \tanh\left( \frac{ r - d_0 }{ r_0 } \right) +s(r) = 1 - \tanh\left( \frac{ r - d_0 }{ r_0 } \right) \f$ </td> <td> {TANH R_0=\f$r_0\f$ D_0=\f$d_0\f$} </td> <td> </td> -</tr> <tr> +</tr> <tr> <td> MATHEVAL </td> <td> \f$ s(r) = FUNC @@ -122,7 +122,7 @@ s(r) = FUNC </table> \attention -Similarly to the \ref MATHEVAL function, the MATHEVAL switching function +Similarly to the \ref MATHEVAL function, the MATHEVAL switching function only works if libmatheval is installed on the system and PLUMED has been linked to it Also notice that using MATHEVAL is much slower than using e.g. RATIONAL. @@ -131,7 +131,7 @@ tests on switching functions with arbitrary form before proceeding to their implementation in C++. For all the switching functions in the above table one can also specify a further (optional) parameter using the parameter -keyword D_MAX to assert that for \f$r>d_{\textrm{max}}\f$ the switching function can be assumed equal to zero. +keyword D_MAX to assert that for \f$r>d_{\textrm{max}}\f$ the switching function can be assumed equal to zero. In this case the function is brought smoothly to zero by stretching and shifting it. \verbatim KEYWORD={RATIONAL R_0=1 D_MAX=3} @@ -154,19 +154,19 @@ for backward compatibility. This might change in the future. */ //+ENDPLUMEDOC -void SwitchingFunction::registerKeywords( Keywords& keys ){ +void SwitchingFunction::registerKeywords( Keywords& keys ) { keys.add("compulsory","R_0","the value of R_0 in the switching function"); keys.add("compulsory","D_0","0.0","the value of D_0 in the switching function"); keys.add("optional","D_MAX","the value at which the switching function can be assumed equal to zero"); keys.add("compulsory","NN","6","the value of n in the switching function (only needed for TYPE=RATIONAL)"); keys.add("compulsory","MM","0","the value of m in the switching function (only needed for TYPE=RATIONAL); 0 implies 2*NN"); keys.add("compulsory","A","the value of a in the switching funciton (only needed for TYPE=SMAP)"); - keys.add("compulsory","B","the value of b in the switching funciton (only needed for TYPE=SMAP)"); + keys.add("compulsory","B","the value of b in the switching funciton (only needed for TYPE=SMAP)"); } -void SwitchingFunction::set(const std::string & definition,std::string& errormsg){ +void SwitchingFunction::set(const std::string & definition,std::string& errormsg) { vector<string> data=Tools::getWords(definition); - if( data.size()<1 ) errormsg="missing all input for switching function"; + if( data.size()<1 ) errormsg="missing all input for switching function"; string name=data[0]; data.erase(data.begin()); invr0=0.0; @@ -193,16 +193,16 @@ void SwitchingFunction::set(const std::string & definition,std::string& errormsg Tools::parseFlag(data,"NOSTRETCH",dontstretch); // this is ignored now if(dontstretch) dostretch=false; double r0; - if(name=="CUBIC"){ - r0 = dmax - d0; + if(name=="CUBIC") { + r0 = dmax - d0; } else { - bool found_r0=Tools::parse(data,"R_0",r0); - if(!found_r0) errormsg="R_0 is required"; + bool found_r0=Tools::parse(data,"R_0",r0); + if(!found_r0) errormsg="R_0 is required"; } invr0=1.0/r0; invr0_2=invr0*invr0; - if(name=="RATIONAL"){ + if(name=="RATIONAL") { type=rational; nn=6; mm=0; @@ -211,17 +211,17 @@ void SwitchingFunction::set(const std::string & definition,std::string& errormsg present=Tools::findKeyword(data,"MM"); if(present && !Tools::parse(data,"MM",mm)) errormsg="could not parse MM"; if(mm==0) mm=2*nn; - } else if(name=="SMAP"){ + } else if(name=="SMAP") { type=smap; present=Tools::findKeyword(data,"A"); if(present && !Tools::parse(data,"A",a)) errormsg="could not parse A"; present=Tools::findKeyword(data,"B"); if(present && !Tools::parse(data,"B",b)) errormsg="could not parse B"; - c=pow(2., static_cast<double>(a)/static_cast<double>(b) ) - 1; + c=pow(2., static_cast<double>(a)/static_cast<double>(b) ) - 1; d = -static_cast<double>(b) / static_cast<double>(a); - } + } else if(name=="Q") { - type=nativeq; + type=nativeq; beta = 50.0; // nm-1 lambda = 1.8; // unitless present=Tools::findKeyword(data,"BETA"); @@ -237,7 +237,7 @@ void SwitchingFunction::set(const std::string & definition,std::string& errormsg else if(name=="CUBIC") type=cubic; else if(name=="TANH") type=tanh; #ifdef __PLUMED_HAS_MATHEVAL - else if(name=="MATHEVAL"){ + else if(name=="MATHEVAL") { type=matheval; std::string func; Tools::parse(data,"FUNC",func); @@ -245,11 +245,11 @@ void SwitchingFunction::set(const std::string & definition,std::string& errormsg char **check_names; int check_count; evaluator_get_variables(evaluator,&check_names,&check_count); - if(check_count!=1){ + if(check_count!=1) { errormsg="wrong number of arguments in MATHEVAL switching function"; return; - } - if(std::string(check_names[0])!="x"){ + } + if(std::string(check_names[0])!="x") { errormsg ="argument should be named 'x'"; return; } @@ -257,12 +257,12 @@ void SwitchingFunction::set(const std::string & definition,std::string& errormsg } #endif else errormsg="cannot understand switching function type '"+name+"'"; - if( !data.empty() ){ - errormsg="found the following rogue keywords in switching function input : "; - for(unsigned i=0;i<data.size();++i) errormsg = errormsg + data[i] + " "; + if( !data.empty() ) { + errormsg="found the following rogue keywords in switching function input : "; + for(unsigned i=0; i<data.size(); ++i) errormsg = errormsg + data[i] + " "; } - if(dostretch && dmax!=std::numeric_limits<double>::max()){ + if(dostretch && dmax!=std::numeric_limits<double>::max()) { double dummy; double s0=calculate(0.0,dummy); double sd=calculate(dmax,dummy); @@ -274,73 +274,73 @@ void SwitchingFunction::set(const std::string & definition,std::string& errormsg std::string SwitchingFunction::description() const { std::ostringstream ostr; ostr<<1./invr0<<". Using "; - if(type==rational){ - ostr<<"rational"; - } else if(type==exponential){ - ostr<<"exponential"; - } else if(type==nativeq){ - ostr<<"nativeq"; - } else if(type==gaussian){ - ostr<<"gaussian"; - } else if(type==smap){ - ostr<<"smap"; - } else if(type==cubic){ - ostr<<"cubic"; - } else if(type==tanh){ - ostr<<"tanh"; + if(type==rational) { + ostr<<"rational"; + } else if(type==exponential) { + ostr<<"exponential"; + } else if(type==nativeq) { + ostr<<"nativeq"; + } else if(type==gaussian) { + ostr<<"gaussian"; + } else if(type==smap) { + ostr<<"smap"; + } else if(type==cubic) { + ostr<<"cubic"; + } else if(type==tanh) { + ostr<<"tanh"; #ifdef __PLUMED_HAS_MATHEVAL - } else if(type==matheval){ - ostr<<"matheval"; + } else if(type==matheval) { + ostr<<"matheval"; #endif - } else{ - plumed_merror("Unknown switching function type"); + } else { + plumed_merror("Unknown switching function type"); } ostr<<" swiching function with parameters d0="<<d0; - if(type==rational){ + if(type==rational) { ostr<<" nn="<<nn<<" mm="<<mm; - } else if(type==nativeq){ + } else if(type==nativeq) { ostr<<" beta="<<beta<<" lambda="<<lambda<<" ref="<<ref; - } else if(type==smap){ + } else if(type==smap) { ostr<<" a="<<a<<" b="<<b; - } else if(type==cubic){ + } else if(type==cubic) { ostr<<" dmax="<<dmax; #ifdef __PLUMED_HAS_MATHEVAL - } else if(type==matheval){ - ostr<<" func="<<evaluator_get_string(evaluator); + } else if(type==matheval) { + ostr<<" func="<<evaluator_get_string(evaluator); #endif } - return ostr.str(); + return ostr.str(); } -double SwitchingFunction::do_rational(double rdist,double&dfunc,int nn,int mm)const{ - double result; - if(2*nn==mm){ +double SwitchingFunction::do_rational(double rdist,double&dfunc,int nn,int mm)const { + double result; + if(2*nn==mm) { // if 2*N==M, then (1.0-rdist^N)/(1.0-rdist^M) = 1.0/(1.0+rdist^N) - double rNdist=Tools::fastpow(rdist,nn-1); - double iden=1.0/(1+rNdist*rdist); - dfunc = -nn*rNdist*iden*iden; - result = iden; - } else { - if(rdist>(1.-100.0*epsilon) && rdist<(1+100.0*epsilon)){ - result=nn/mm; - dfunc=0.5*nn*(nn-mm)/mm; - }else{ - double rNdist=Tools::fastpow(rdist,nn-1); - double rMdist=Tools::fastpow(rdist,mm-1); - double num = 1.-rNdist*rdist; - double iden = 1./(1.-rMdist*rdist); - double func = num*iden; - result = func; - dfunc = ((-nn*rNdist*iden)+(func*(iden*mm)*rMdist)); - } - } - return result; + double rNdist=Tools::fastpow(rdist,nn-1); + double iden=1.0/(1+rNdist*rdist); + dfunc = -nn*rNdist*iden*iden; + result = iden; + } else { + if(rdist>(1.-100.0*epsilon) && rdist<(1+100.0*epsilon)) { + result=nn/mm; + dfunc=0.5*nn*(nn-mm)/mm; + } else { + double rNdist=Tools::fastpow(rdist,nn-1); + double rMdist=Tools::fastpow(rdist,mm-1); + double num = 1.-rNdist*rdist; + double iden = 1./(1.-rMdist*rdist); + double func = num*iden; + result = func; + dfunc = ((-nn*rNdist*iden)+(func*(iden*mm)*rMdist)); + } + } + return result; } -double SwitchingFunction::calculateSqr(double distance2,double&dfunc)const{ - if(type==rational && nn%2==0 && mm%2==0 && d0==0.0){ - if(distance2>dmax_2){ +double SwitchingFunction::calculateSqr(double distance2,double&dfunc)const { + if(type==rational && nn%2==0 && mm%2==0 && d0==0.0) { + if(distance2>dmax_2) { dfunc=0.0; return 0.0; } @@ -358,50 +358,50 @@ double SwitchingFunction::calculateSqr(double distance2,double&dfunc)const{ } } -double SwitchingFunction::calculate(double distance,double&dfunc)const{ +double SwitchingFunction::calculate(double distance,double&dfunc)const { plumed_massert(init,"you are trying to use an unset SwitchingFunction"); - if(distance>dmax){ + if(distance>dmax) { dfunc=0.0; return 0.0; } const double rdist = (distance-d0)*invr0; double result; - if(rdist<=0.){ - result=1.; - dfunc=0.0; - }else{ - if(type==smap){ - double sx=c*pow( rdist, a ); - result=pow( 1.0 + sx, d ); - dfunc=-b*sx/rdist*result/(1.0+sx); - } else if(type==rational){ + if(rdist<=0.) { + result=1.; + dfunc=0.0; + } else { + if(type==smap) { + double sx=c*pow( rdist, a ); + result=pow( 1.0 + sx, d ); + dfunc=-b*sx/rdist*result/(1.0+sx); + } else if(type==rational) { result=do_rational(rdist,dfunc,nn,mm); - }else if(type==exponential){ + } else if(type==exponential) { result=exp(-rdist); dfunc=-result; - }else if(type==nativeq){ + } else if(type==nativeq) { double rdist2 = beta*(distance - lambda * ref); double exprdist=exp(rdist2); result=1./(1.+exprdist); dfunc=-exprdist/(1.+exprdist)/(1.+exprdist); - }else if(type==gaussian){ + } else if(type==gaussian) { result=exp(-0.5*rdist*rdist); dfunc=-rdist*result; - }else if(type==cubic){ + } else if(type==cubic) { double tmp1=rdist-1, tmp2=(1+2*rdist); result=tmp1*tmp1*tmp2; dfunc=2*tmp1*tmp2 + 2*tmp1*tmp1; - }else if(type==tanh){ + } else if(type==tanh) { double tmp1=std::tanh(rdist); result = 1.0 - tmp1; dfunc=-(1-tmp1*tmp1); #ifdef __PLUMED_HAS_MATHEVAL - }else if(type==matheval){ + } else if(type==matheval) { result=evaluator_evaluate_x(evaluator,rdist); dfunc=evaluator_evaluate_x(evaluator_deriv,rdist); #endif - }else plumed_merror("Unknown switching function type"); + } else plumed_merror("Unknown switching function type"); // this is for the chain rule: dfunc*=invr0; // this is because calculate() sets dfunc to the derivative divided times the distance. @@ -467,7 +467,7 @@ SwitchingFunction::SwitchingFunction(const SwitchingFunction&sf): #endif } -SwitchingFunction & SwitchingFunction::operator=(const SwitchingFunction& sf){ +SwitchingFunction & SwitchingFunction::operator=(const SwitchingFunction& sf) { if(&sf==this) return *this; init=sf.init; type=sf.type; @@ -497,7 +497,7 @@ SwitchingFunction & SwitchingFunction::operator=(const SwitchingFunction& sf){ } -void SwitchingFunction::set(int nn,int mm,double r0,double d0){ +void SwitchingFunction::set(int nn,int mm,double r0,double d0) { init=true; type=rational; if(mm==0) mm=2*nn; @@ -526,7 +526,7 @@ double SwitchingFunction::get_dmax2() const { return dmax_2; } -SwitchingFunction::~SwitchingFunction(){ +SwitchingFunction::~SwitchingFunction() { #ifdef __PLUMED_HAS_MATHEVAL if(evaluator) evaluator_destroy(evaluator); if(evaluator_deriv) evaluator_destroy(evaluator_deriv); diff --git a/src/tools/SwitchingFunction.h b/src/tools/SwitchingFunction.h index 4bcf27926..379280da4 100644 --- a/src/tools/SwitchingFunction.h +++ b/src/tools/SwitchingFunction.h @@ -37,7 +37,7 @@ class Keywords; /// the second all (calculateSqr()) allows to skip the calculation /// of a square root in some case, thus potentially increasing /// performances. -class SwitchingFunction{ +class SwitchingFunction { /// This is to check that switching function has been initialized bool init; /// Type of function @@ -81,7 +81,7 @@ public: SwitchingFunction & operator=(const SwitchingFunction&); /// Set a "rational" switching function. /// Notice that a d_max is set automatically to a value such that -/// f(d_max)=0.00001. +/// f(d_max)=0.00001. void set(int nn,int mm,double r_0,double d_0); /// Set an arbitrary switching function. /// Parse the string in definition and possibly returns errors @@ -104,7 +104,7 @@ public: double get_d0() const; /// Returns r0 double get_r0() const; -/// Return dmax +/// Return dmax double get_dmax() const; /// Return dmax squared double get_dmax2() const; diff --git a/src/tools/Tensor.cpp b/src/tools/Tensor.cpp index ad8f2ae6d..d063e28cf 100644 --- a/src/tools/Tensor.cpp +++ b/src/tools/Tensor.cpp @@ -22,15 +22,15 @@ #include "Tensor.h" #include "Exception.h" -namespace PLMD{ +namespace PLMD { /// Small auxiliary class. /// I use it to test a few things that I am scary of and could introduce bugs. /// It checks at startup that Tensor satifies some requirement so as to allow /// accessing a vector of tensors as a 9 times longer array of doubles. -static class TensorChecks{ +static class TensorChecks { public: - TensorChecks(){ + TensorChecks() { if(sizeof(Tensor)==9*sizeof(double)) return; plumed_merror("sizeof(Tensor)!=9*sizeof(double). PLUMED cannot work properly in these conditions."); } diff --git a/src/tools/Tensor.h b/src/tools/Tensor.h index 8e95e21b9..7cd6515c8 100644 --- a/src/tools/Tensor.h +++ b/src/tools/Tensor.h @@ -30,7 +30,7 @@ #include "Exception.h" #endif -namespace PLMD{ +namespace PLMD { /** \ingroup TOOLBOX @@ -182,18 +182,18 @@ public: }; template<unsigned n,unsigned m> -TensorGeneric<n,m>::TensorGeneric(){ +TensorGeneric<n,m>::TensorGeneric() { LoopUnroller<n*m>::_zero(d); } template<unsigned n,unsigned m> -TensorGeneric<n,m>::TensorGeneric(const VectorGeneric<n>&v1,const VectorGeneric<m>&v2){ - for(unsigned i=0;i<n;i++)for(unsigned j=0;j<m;j++)d[i*m+j]=v1[i]*v2[j]; +TensorGeneric<n,m>::TensorGeneric(const VectorGeneric<n>&v1,const VectorGeneric<m>&v2) { + for(unsigned i=0; i<n; i++)for(unsigned j=0; j<m; j++)d[i*m+j]=v1[i]*v2[j]; } template<> inline -TensorGeneric<2,2>::TensorGeneric(double d00,double d01,double d10,double d11){ +TensorGeneric<2,2>::TensorGeneric(double d00,double d01,double d10,double d11) { d[0]=d00; d[1]=d01; d[2]=d10; @@ -202,7 +202,7 @@ TensorGeneric<2,2>::TensorGeneric(double d00,double d01,double d10,double d11){ template<> inline -TensorGeneric<3,3>::TensorGeneric(double d00,double d01,double d02,double d10,double d11,double d12,double d20,double d21,double d22){ +TensorGeneric<3,3>::TensorGeneric(double d00,double d01,double d02,double d10,double d11,double d12,double d20,double d21,double d22) { d[0]=d00; d[1]=d01; d[2]=d02; @@ -215,12 +215,12 @@ TensorGeneric<3,3>::TensorGeneric(double d00,double d01,double d02,double d10,do } template<unsigned n,unsigned m> -void TensorGeneric<n,m>::zero(){ +void TensorGeneric<n,m>::zero() { LoopUnroller<n*m>::_zero(d); } template<unsigned n,unsigned m> -double & TensorGeneric<n,m>::operator() (unsigned i,unsigned j){ +double & TensorGeneric<n,m>::operator() (unsigned i,unsigned j) { #ifdef _GLIBCXX_DEBUG plumed_assert(i<n && j<m); #endif @@ -228,7 +228,7 @@ double & TensorGeneric<n,m>::operator() (unsigned i,unsigned j){ } template<unsigned n,unsigned m> -const double & TensorGeneric<n,m>::operator() (unsigned i,unsigned j)const{ +const double & TensorGeneric<n,m>::operator() (unsigned i,unsigned j)const { #ifdef _GLIBCXX_DEBUG plumed_assert(i<n && j<m); #endif @@ -236,228 +236,228 @@ const double & TensorGeneric<n,m>::operator() (unsigned i,unsigned j)const{ } template<unsigned n,unsigned m> -TensorGeneric<n,m>& TensorGeneric<n,m>::operator +=(const TensorGeneric<n,m>& b){ +TensorGeneric<n,m>& TensorGeneric<n,m>::operator +=(const TensorGeneric<n,m>& b) { LoopUnroller<n*m>::_add(d,b.d); return *this; } template<unsigned n,unsigned m> -TensorGeneric<n,m>& TensorGeneric<n,m>::operator -=(const TensorGeneric<n,m>& b){ +TensorGeneric<n,m>& TensorGeneric<n,m>::operator -=(const TensorGeneric<n,m>& b) { LoopUnroller<n*m>::_sub(d,b.d); return *this; } template<unsigned n,unsigned m> -TensorGeneric<n,m>& TensorGeneric<n,m>::operator *=(double s){ +TensorGeneric<n,m>& TensorGeneric<n,m>::operator *=(double s) { LoopUnroller<n*m>::_mul(d,s); return *this; } template<unsigned n,unsigned m> -TensorGeneric<n,m>& TensorGeneric<n,m>::operator /=(double s){ +TensorGeneric<n,m>& TensorGeneric<n,m>::operator /=(double s) { LoopUnroller<n*m>::_mul(d,1.0/s); return *this; } template<unsigned n,unsigned m> -TensorGeneric<n,m> TensorGeneric<n,m>::operator+()const{ +TensorGeneric<n,m> TensorGeneric<n,m>::operator+()const { return *this; } template<unsigned n,unsigned m> -TensorGeneric<n,m> TensorGeneric<n,m>::operator-()const{ +TensorGeneric<n,m> TensorGeneric<n,m>::operator-()const { TensorGeneric<n,m> r; LoopUnroller<n*m>::_neg(r.d,d); return r; } template<unsigned n,unsigned m> -TensorGeneric<n,m>& TensorGeneric<n,m>::setCol(unsigned j,const VectorGeneric<n> & c){ - for(unsigned i=0;i<n;++i) (*this)(i,j)=c(i); +TensorGeneric<n,m>& TensorGeneric<n,m>::setCol(unsigned j,const VectorGeneric<n> & c) { + for(unsigned i=0; i<n; ++i) (*this)(i,j)=c(i); return *this; } template<unsigned n,unsigned m> -TensorGeneric<n,m>& TensorGeneric<n,m>::setRow(unsigned i,const VectorGeneric<m> & r){ - for(unsigned j=0;j<m;++j) (*this)(i,j)=r(j); +TensorGeneric<n,m>& TensorGeneric<n,m>::setRow(unsigned i,const VectorGeneric<m> & r) { + for(unsigned j=0; j<m; ++j) (*this)(i,j)=r(j); return *this; } template<unsigned n,unsigned m> -VectorGeneric<n> TensorGeneric<n,m>::getCol(unsigned j)const{ +VectorGeneric<n> TensorGeneric<n,m>::getCol(unsigned j)const { VectorGeneric<n> v; - for(unsigned i=0;i<n;++i) v(i)=(*this)(i,j); + for(unsigned i=0; i<n; ++i) v(i)=(*this)(i,j); return v; } template<unsigned n,unsigned m> -VectorGeneric<m> TensorGeneric<n,m>::getRow(unsigned i)const{ +VectorGeneric<m> TensorGeneric<n,m>::getRow(unsigned i)const { VectorGeneric<m> v; - for(unsigned j=0;j<m;++j) v(j)=(*this)(i,j); + for(unsigned j=0; j<m; ++j) v(j)=(*this)(i,j); return v; } template<unsigned n,unsigned m> -TensorGeneric<n,m> operator+(const TensorGeneric<n,m>&t1,const TensorGeneric<n,m>&t2){ +TensorGeneric<n,m> operator+(const TensorGeneric<n,m>&t1,const TensorGeneric<n,m>&t2) { TensorGeneric<n,m> t(t1); t+=t2; return t; } template<unsigned n,unsigned m> -TensorGeneric<n,m> operator-(const TensorGeneric<n,m>&t1,const TensorGeneric<n,m>&t2){ +TensorGeneric<n,m> operator-(const TensorGeneric<n,m>&t1,const TensorGeneric<n,m>&t2) { TensorGeneric<n,m> t(t1); t-=t2; return t; } template<unsigned n,unsigned m> -TensorGeneric<n,m> operator*(const TensorGeneric<n,m>&t1,double s){ +TensorGeneric<n,m> operator*(const TensorGeneric<n,m>&t1,double s) { TensorGeneric<n,m> t(t1); t*=s; return t; } template<unsigned n,unsigned m> -TensorGeneric<n,m> operator*(double s,const TensorGeneric<n,m>&t1){ +TensorGeneric<n,m> operator*(double s,const TensorGeneric<n,m>&t1) { return t1*s; } template<unsigned n,unsigned m> -TensorGeneric<n,m> operator/(const TensorGeneric<n,m>&t1,double s){ +TensorGeneric<n,m> operator/(const TensorGeneric<n,m>&t1,double s) { return t1*(1.0/s); } template<> inline -double TensorGeneric<3,3>::determinant()const{ +double TensorGeneric<3,3>::determinant()const { return - d[0]*d[4]*d[8] - + d[1]*d[5]*d[6] - + d[2]*d[3]*d[7] - - d[0]*d[5]*d[7] - - d[1]*d[3]*d[8] - - d[2]*d[4]*d[6]; + d[0]*d[4]*d[8] + + d[1]*d[5]*d[6] + + d[2]*d[3]*d[7] + - d[0]*d[5]*d[7] + - d[1]*d[3]*d[8] + - d[2]*d[4]*d[6]; } template<unsigned n,unsigned m> inline -TensorGeneric<n,n> TensorGeneric<n,m>::identity(){ +TensorGeneric<n,n> TensorGeneric<n,m>::identity() { TensorGeneric<n,n> t; - for(unsigned i=0;i<n;i++) t(i,i)=1.0; + for(unsigned i=0; i<n; i++) t(i,i)=1.0; return t; } template<unsigned n,unsigned m> -TensorGeneric<m,n> TensorGeneric<n,m>::transpose()const{ +TensorGeneric<m,n> TensorGeneric<n,m>::transpose()const { TensorGeneric<m,n> t; - for(unsigned i=0;i<m;i++)for(unsigned j=0;j<n;j++) t(i,j)=(*this)(j,i); + for(unsigned i=0; i<m; i++)for(unsigned j=0; j<n; j++) t(i,j)=(*this)(j,i); return t; } template<> inline -TensorGeneric<3,3> TensorGeneric<3,3>::inverse()const{ +TensorGeneric<3,3> TensorGeneric<3,3>::inverse()const { TensorGeneric t; double invdet=1.0/determinant(); - for(unsigned i=0;i<3;i++) for(unsigned j=0;j<3;j++) - t(j,i)=invdet*( (*this)((i+1)%3,(j+1)%3)*(*this)((i+2)%3,(j+2)%3) - -(*this)((i+1)%3,(j+2)%3)*(*this)((i+2)%3,(j+1)%3)); + for(unsigned i=0; i<3; i++) for(unsigned j=0; j<3; j++) + t(j,i)=invdet*( (*this)((i+1)%3,(j+1)%3)*(*this)((i+2)%3,(j+2)%3) + -(*this)((i+1)%3,(j+2)%3)*(*this)((i+2)%3,(j+1)%3)); return t; } template<unsigned n,unsigned m,unsigned l> -TensorGeneric<n,l> matmul(const TensorGeneric<n,m>&a,const TensorGeneric<m,l>&b){ +TensorGeneric<n,l> matmul(const TensorGeneric<n,m>&a,const TensorGeneric<m,l>&b) { TensorGeneric<n,l> t; - for(unsigned i=0;i<n;i++) for(unsigned j=0;j<l;j++) for(unsigned k=0;k<m;k++) { - t(i,j)+=a(i,k)*b(k,j); - } + for(unsigned i=0; i<n; i++) for(unsigned j=0; j<l; j++) for(unsigned k=0; k<m; k++) { + t(i,j)+=a(i,k)*b(k,j); + } return t; } template<unsigned n,unsigned m> -VectorGeneric<n> matmul(const TensorGeneric<n,m>&a,const VectorGeneric<m>&b){ +VectorGeneric<n> matmul(const TensorGeneric<n,m>&a,const VectorGeneric<m>&b) { VectorGeneric<n> t; - for(unsigned i=0;i<n;i++) for(unsigned j=0;j<m;j++) t(i)+=a(i,j)*b(j); + for(unsigned i=0; i<n; i++) for(unsigned j=0; j<m; j++) t(i)+=a(i,j)*b(j); return t; } template<unsigned n,unsigned m> -VectorGeneric<n> matmul(const VectorGeneric<m>&a,const TensorGeneric<m,n>&b){ +VectorGeneric<n> matmul(const VectorGeneric<m>&a,const TensorGeneric<m,n>&b) { VectorGeneric<n> t; - for(unsigned i=0;i<n;i++) for(unsigned j=0;j<m;j++) t(i)+=a(j)*b(j,i); + for(unsigned i=0; i<n; i++) for(unsigned j=0; j<m; j++) t(i)+=a(j)*b(j,i); return t; } template<unsigned n_> -double matmul(const VectorGeneric<n_>&a,const VectorGeneric<n_>&b){ +double matmul(const VectorGeneric<n_>&a,const VectorGeneric<n_>&b) { return dotProduct(a,b); } template<unsigned n,unsigned m,unsigned l,unsigned i> -TensorGeneric<n,i> matmul(const TensorGeneric<n,m>&a,const TensorGeneric<m,l>&b,const TensorGeneric<l,i>&c){ +TensorGeneric<n,i> matmul(const TensorGeneric<n,m>&a,const TensorGeneric<m,l>&b,const TensorGeneric<l,i>&c) { return matmul(matmul(a,b),c); } template<unsigned n,unsigned m,unsigned l> -VectorGeneric<n> matmul(const TensorGeneric<n,m>&a,const TensorGeneric<m,l>&b,const VectorGeneric<l>&c){ +VectorGeneric<n> matmul(const TensorGeneric<n,m>&a,const TensorGeneric<m,l>&b,const VectorGeneric<l>&c) { return matmul(matmul(a,b),c); } -template<unsigned n,unsigned m,unsigned l> -VectorGeneric<l> matmul(const VectorGeneric<n>&a,const TensorGeneric<n,m>&b,const TensorGeneric<m,l>&c){ +template<unsigned n,unsigned m,unsigned l> +VectorGeneric<l> matmul(const VectorGeneric<n>&a,const TensorGeneric<n,m>&b,const TensorGeneric<m,l>&c) { return matmul(matmul(a,b),c); } template<unsigned n,unsigned m> -double matmul(const VectorGeneric<n>&a,const TensorGeneric<n,m>&b,const VectorGeneric<m>&c){ +double matmul(const VectorGeneric<n>&a,const TensorGeneric<n,m>&b,const VectorGeneric<m>&c) { return matmul(matmul(a,b),c); } inline -double determinant(const TensorGeneric<3,3>&t){ +double determinant(const TensorGeneric<3,3>&t) { return t.determinant(); } inline -TensorGeneric<3,3> inverse(const TensorGeneric<3,3>&t){ +TensorGeneric<3,3> inverse(const TensorGeneric<3,3>&t) { return t.inverse(); } template<unsigned n,unsigned m> -TensorGeneric<n,m> transpose(const TensorGeneric<m,n>&t){ +TensorGeneric<n,m> transpose(const TensorGeneric<m,n>&t) { return t.transpose(); } template<unsigned n,unsigned m> -TensorGeneric<n,m> extProduct(const VectorGeneric<n>&v1,const VectorGeneric<m>&v2){ +TensorGeneric<n,m> extProduct(const VectorGeneric<n>&v1,const VectorGeneric<m>&v2) { return TensorGeneric<n,m>(v1,v2); } inline -TensorGeneric<3,3> dcrossDv1(const VectorGeneric<3>&v1,const VectorGeneric<3>&v2){ +TensorGeneric<3,3> dcrossDv1(const VectorGeneric<3>&v1,const VectorGeneric<3>&v2) { (void) v1; // this is to avoid warnings. still the syntax of this function is a bit dummy... return TensorGeneric<3,3>( - 0.0, v2[2],-v2[1], - -v2[2], 0.0, v2[0], - v2[1],-v2[0], 0.0); + 0.0, v2[2],-v2[1], + -v2[2], 0.0, v2[0], + v2[1],-v2[0], 0.0); } inline -TensorGeneric<3,3> dcrossDv2(const VectorGeneric<3>&v1,const VectorGeneric<3>&v2){ +TensorGeneric<3,3> dcrossDv2(const VectorGeneric<3>&v1,const VectorGeneric<3>&v2) { (void) v2; // this is to avoid warnings. still the syntax of this function is a bit dummy... return TensorGeneric<3,3>( - 0.0,-v1[2],v1[1], - v1[2],0.0,-v1[0], - -v1[1],v1[0],0.0); + 0.0,-v1[2],v1[1], + v1[2],0.0,-v1[0], + -v1[1],v1[0],0.0); } template<unsigned n,unsigned m> -std::ostream & operator<<(std::ostream &os, const TensorGeneric<n,m>& t){ - for(unsigned i=0;i<n;i++)for(unsigned j=0;j<m;j++){ - if(i!=(n-1) || j!=(m-1)) os<<t(i,j)<<" "; - else os<<t(i,j); - } +std::ostream & operator<<(std::ostream &os, const TensorGeneric<n,m>& t) { + for(unsigned i=0; i<n; i++)for(unsigned j=0; j<m; j++) { + if(i!=(n-1) || j!=(m-1)) os<<t(i,j)<<" "; + else os<<t(i,j); + } return os; } @@ -471,32 +471,32 @@ typedef TensorGeneric<4,4> Tensor4d; typedef Tensor3d Tensor; inline -TensorGeneric<3,3> VcrossTensor(const VectorGeneric<3>&v1,const TensorGeneric<3,3>&v2){ +TensorGeneric<3,3> VcrossTensor(const VectorGeneric<3>&v1,const TensorGeneric<3,3>&v2) { - TensorGeneric<3,3> t; - for(unsigned i=0;i<3;i++){ - t.setRow(i,matmul(dcrossDv2(v1,v1),v2.getRow(i))); - } - return t; + TensorGeneric<3,3> t; + for(unsigned i=0; i<3; i++) { + t.setRow(i,matmul(dcrossDv2(v1,v1),v2.getRow(i))); + } + return t; } inline -TensorGeneric<3,3> VcrossTensor(const TensorGeneric<3,3>&v2,const VectorGeneric<3>&v1){ - TensorGeneric<3,3> t; - for(unsigned i=0;i<3;i++){ - t.setRow(i,-matmul(dcrossDv2(v1,v1),v2.getRow(i))); - } - return t; +TensorGeneric<3,3> VcrossTensor(const TensorGeneric<3,3>&v2,const VectorGeneric<3>&v1) { + TensorGeneric<3,3> t; + for(unsigned i=0; i<3; i++) { + t.setRow(i,-matmul(dcrossDv2(v1,v1),v2.getRow(i))); + } + return t; } inline -TensorGeneric<3,3> deriNorm(const VectorGeneric<3>&v1,const TensorGeneric<3,3>&v2){ +TensorGeneric<3,3> deriNorm(const VectorGeneric<3>&v1,const TensorGeneric<3,3>&v2) { // delta(v) = delta(v1/v1.norm) = 1/v1.norm*(delta(v1) - (v.delta(v1))cross v; double over_norm = 1./v1.modulo(); return over_norm*(v2 - over_norm*over_norm*(extProduct(matmul(v2,v1),v1))); } - + diff --git a/src/tools/Tools.cpp b/src/tools/Tools.cpp index 02256a1f1..f5af5a903 100644 --- a/src/tools/Tools.cpp +++ b/src/tools/Tools.cpp @@ -28,31 +28,31 @@ #include <iostream> using namespace std; -namespace PLMD{ +namespace PLMD { template<class T> -bool Tools::convertToAny(const string & str,T & t){ - istringstream istr(str.c_str()); - bool ok=static_cast<bool>(istr>>t); - if(!ok) return false; - string remaining; - istr>>remaining; - return remaining.length()==0; +bool Tools::convertToAny(const string & str,T & t) { + istringstream istr(str.c_str()); + bool ok=static_cast<bool>(istr>>t); + if(!ok) return false; + string remaining; + istr>>remaining; + return remaining.length()==0; } -bool Tools::convert(const string & str,int & t){ - return convertToAny(str,t); +bool Tools::convert(const string & str,int & t) { + return convertToAny(str,t); } -bool Tools::convert(const string & str,long int & t){ - return convertToAny(str,t); +bool Tools::convert(const string & str,long int & t) { + return convertToAny(str,t); } -bool Tools::convert(const string & str,unsigned & t){ - return convertToAny(str,t); +bool Tools::convert(const string & str,unsigned & t) { + return convertToAny(str,t); } -bool Tools::convert(const string & str,AtomNumber &a){ +bool Tools::convert(const string & str,AtomNumber &a) { unsigned i; bool r=convert(str,i); if(r) a.setSerial(i); @@ -60,57 +60,57 @@ bool Tools::convert(const string & str,AtomNumber &a){ } template<class T> -bool Tools::convertToReal(const string & str,T & t){ - if(str=="PI" || str=="+PI" || str=="+pi" || str=="pi"){ - t=pi; return true; - } else if(str=="-PI" || str=="-pi"){ - t=-pi; return true; - } else if( str.find("PI")!=std::string::npos ){ - std::size_t pi_start=str.find_first_of("PI"); - if(str.substr(pi_start)!="PI") return false; - istringstream nstr(str.substr(0,pi_start)); - T ff=0.0; bool ok=static_cast<bool>(nstr>>ff); - if(!ok) return false; - t=ff*pi; - std::string remains; nstr>>remains; - return remains.length()==0; - } else if( str.find("pi")!=std::string::npos ){ - std::size_t pi_start=str.find_first_of("pi"); - if(str.substr(pi_start)!="pi") return false; - istringstream nstr(str.substr(0,pi_start)); - T ff=0.0; bool ok=static_cast<bool>(nstr>>ff); - if(!ok) return false; - t=ff*pi; - std::string remains; nstr>>remains; - return remains.length()==0; - } else if(str=="NAN"){ - t=NAN; - return true; - } - return convertToAny(str,t); +bool Tools::convertToReal(const string & str,T & t) { + if(str=="PI" || str=="+PI" || str=="+pi" || str=="pi") { + t=pi; return true; + } else if(str=="-PI" || str=="-pi") { + t=-pi; return true; + } else if( str.find("PI")!=std::string::npos ) { + std::size_t pi_start=str.find_first_of("PI"); + if(str.substr(pi_start)!="PI") return false; + istringstream nstr(str.substr(0,pi_start)); + T ff=0.0; bool ok=static_cast<bool>(nstr>>ff); + if(!ok) return false; + t=ff*pi; + std::string remains; nstr>>remains; + return remains.length()==0; + } else if( str.find("pi")!=std::string::npos ) { + std::size_t pi_start=str.find_first_of("pi"); + if(str.substr(pi_start)!="pi") return false; + istringstream nstr(str.substr(0,pi_start)); + T ff=0.0; bool ok=static_cast<bool>(nstr>>ff); + if(!ok) return false; + t=ff*pi; + std::string remains; nstr>>remains; + return remains.length()==0; + } else if(str=="NAN") { + t=NAN; + return true; + } + return convertToAny(str,t); } -bool Tools::convert(const string & str,float & t){ - return convertToReal(str,t); +bool Tools::convert(const string & str,float & t) { + return convertToReal(str,t); } -bool Tools::convert(const string & str,double & t){ - return convertToReal(str,t); +bool Tools::convert(const string & str,double & t) { + return convertToReal(str,t); } -bool Tools::convert(const string & str,long double & t){ - return convertToReal(str,t); +bool Tools::convert(const string & str,long double & t) { + return convertToReal(str,t); } -bool Tools::convert(const string & str,string & t){ - t=str; - return true; +bool Tools::convert(const string & str,string & t) { + t=str; + return true; } -vector<string> Tools::getWords(const string & line,const char* separators,int * parlevel,const char* parenthesis){ +vector<string> Tools::getWords(const string & line,const char* separators,int * parlevel,const char* parenthesis) { plumed_massert(strlen(parenthesis)==1,"multiple parenthesis type not available"); plumed_massert(parenthesis[0]=='(' || parenthesis[0]=='[' || parenthesis[0]=='{', - "only ( [ { allowed as parenthesis"); + "only ( [ { allowed as parenthesis"); if(!separators) separators=" \t\n"; const string sep(separators); char openpar=parenthesis[0]; @@ -122,25 +122,25 @@ vector<string> Tools::getWords(const string & line,const char* separators,int * string word; int parenthesisLevel=0; if(parlevel) parenthesisLevel=*parlevel; - for(unsigned i=0;i<line.length();i++){ + for(unsigned i=0; i<line.length(); i++) { bool found=false; bool onParenthesis=false; if(line[i]==openpar || line[i]==closepar) onParenthesis=true; - if(line[i]==closepar){ + if(line[i]==closepar) { parenthesisLevel--; plumed_massert(parenthesisLevel>=0,"Extra closed parenthesis in '" + line + "'"); } - if(parenthesisLevel==0) for(unsigned j=0;j<sep.length();j++) if(line[i]==sep[j]) found=true; -// If at parenthesis level zero (outer) + if(parenthesisLevel==0) for(unsigned j=0; j<sep.length(); j++) if(line[i]==sep[j]) found=true; +// If at parenthesis level zero (outer) if(!(parenthesisLevel==0 && (found||onParenthesis))) word.push_back(line[i]); if(line[i]==openpar) parenthesisLevel++; - if(found && word.length()>0){ + if(found && word.length()>0) { if(!parlevel) plumed_massert(parenthesisLevel==0,"Unmatching parenthesis in '" + line + "'"); words.push_back(word); word.clear(); } } - if(word.length()>0){ + if(word.length()>0) { if(!parlevel) plumed_massert(parenthesisLevel==0,"Unmatching parenthesis in '" + line + "'"); words.push_back(word); } @@ -148,34 +148,34 @@ vector<string> Tools::getWords(const string & line,const char* separators,int * return words; } -bool Tools::getParsedLine(IFile& ifile,vector<string> & words){ +bool Tools::getParsedLine(IFile& ifile,vector<string> & words) { string line(""); words.clear(); bool stat; bool inside=false; int parlevel=0; bool mergenext=false; - while((stat=ifile.getline(line))){ + while((stat=ifile.getline(line))) { trimComments(line); trim(line); if(line.length()==0) continue; vector<string> w=getWords(line,NULL,&parlevel); if(w.empty()) continue; - if(inside && *(w.begin())=="..."){ + if(inside && *(w.begin())=="...") { inside=false; if(w.size()==2) plumed_massert(w[1]==words[0],"second word in terminating \"...\" lines, if present, should be equal to first word of directive"); plumed_massert(w.size()<=2,"terminating \"...\" lines cannot consist of more than two words"); w.clear(); - }else if(*(w.end()-1)=="..."){ + } else if(*(w.end()-1)=="...") { inside=true; w.erase(w.end()-1); }; int i0=0; - if(mergenext && words.size()>0 && w.size()>0){ + if(mergenext && words.size()>0 && w.size()>0) { words[words.size()-1]+=" "+w[0]; i0=1; } - for(unsigned i=i0;i<w.size();++i) words.push_back(w[i]); + for(unsigned i=i0; i<w.size(); ++i) words.push_back(w[i]); mergenext=(parlevel>0); if(!inside)break; } @@ -185,13 +185,13 @@ bool Tools::getParsedLine(IFile& ifile,vector<string> & words){ } -bool Tools::getline(FILE* fp,string & line){ +bool Tools::getline(FILE* fp,string & line) { line=""; const int bufferlength=1024; char buffer[bufferlength]; bool ret; - for(int i=0;i<bufferlength;i++) buffer[i]='\0'; - while((ret=fgets(buffer,bufferlength,fp))){ + for(int i=0; i<bufferlength; i++) buffer[i]='\0'; + while((ret=fgets(buffer,bufferlength,fp))) { line.append(buffer); unsigned ss=strlen(buffer); if(ss>0) if(buffer[ss-1]=='\n') break; @@ -201,28 +201,28 @@ bool Tools::getline(FILE* fp,string & line){ return ret; } -void Tools::trim(string & s){ +void Tools::trim(string & s) { size_t n=s.find_last_not_of(" \t"); s=s.substr(0,n+1); } -void Tools::trimComments(string & s){ +void Tools::trimComments(string & s) { size_t n=s.find_first_of("#"); s=s.substr(0,n); } -bool Tools::getKey(vector<string>& line,const string & key,string & s,int rep){ +bool Tools::getKey(vector<string>& line,const string & key,string & s,int rep) { s.clear(); - for(auto p=line.begin();p!=line.end();++p){ + for(auto p=line.begin(); p!=line.end(); ++p) { if((*p).length()==0) continue; string x=(*p).substr(0,key.length()); - if(x==key){ + if(x==key) { if((*p).length()==key.length())return false; string tmp=(*p).substr(key.length(),(*p).length()); line.erase(p); s=tmp; const std::string multi("@replicas:"); - if(rep>=0 && startWith(s,multi)){ + if(rep>=0 && startWith(s,multi)) { s=s.substr(multi.length(),s.length()); std::vector<std::string> words=getWords(s,"\t\n ,"); plumed_assert(rep<words.size()); @@ -234,9 +234,9 @@ bool Tools::getKey(vector<string>& line,const string & key,string & s,int rep){ return false; } -void Tools::interpretRanges(std::vector<std::string>&s){ +void Tools::interpretRanges(std::vector<std::string>&s) { vector<string> news; - for(const auto & p :s){ + for(const auto & p :s) { news.push_back(p); size_t dash=p.find("-"); if(dash==string::npos) continue; @@ -245,23 +245,23 @@ void Tools::interpretRanges(std::vector<std::string>&s){ int stride=1; int second; size_t colon=p.substr(dash+1).find(":"); - if(colon!=string::npos){ + if(colon!=string::npos) { if(!Tools::convert(p.substr(dash+1).substr(0,colon),second) || - !Tools::convert(p.substr(dash+1).substr(colon+1),stride)) continue; + !Tools::convert(p.substr(dash+1).substr(colon+1),stride)) continue; } else { if(!Tools::convert(p.substr(dash+1),second)) continue; } news.resize(news.size()-1); - if(first<=second){ + if(first<=second) { plumed_massert(stride>0,"interpreting ranges "+ p + ", stride should be positive"); - for(int i=first;i<=second;i+=stride){ + for(int i=first; i<=second; i+=stride) { string ss; convert(i,ss); news.push_back(ss); } } else { plumed_massert(stride<0,"interpreting ranges "+ p + ", stride should be positive"); - for(int i=first;i>=second;i+=stride){ + for(int i=first; i>=second; i+=stride) { string ss; convert(i,ss); news.push_back(ss); @@ -271,25 +271,25 @@ void Tools::interpretRanges(std::vector<std::string>&s){ s=news; } -void Tools::interpretLabel(vector<string>&s){ +void Tools::interpretLabel(vector<string>&s) { if(s.size()<2)return; string s0=s[0]; unsigned l=s0.length(); if(l<1) return; - if(s0[l-1]==':'){ + if(s0[l-1]==':') { s[0]=s[1]; s[1]="LABEL="+s0.substr(0,l-1); } } -vector<string> Tools::ls(const string&d){ +vector<string> Tools::ls(const string&d) { DIR*dir; vector<string> result; - if ((dir=opendir(d.c_str()))){ + if ((dir=opendir(d.c_str()))) { #if defined(__PLUMED_HAS_READDIR_R) struct dirent ent; #endif - while(true){ + while(true) { struct dirent *res; #if defined(__PLUMED_HAS_READDIR_R) readdir_r(dir,&ent,&res); @@ -309,16 +309,16 @@ vector<string> Tools::ls(const string&d){ return result; } -void Tools::stripLeadingAndTrailingBlanks( std::string& str ){ +void Tools::stripLeadingAndTrailingBlanks( std::string& str ) { std::size_t first=str.find_first_not_of(' '); std::size_t last=str.find_last_not_of(' '); if( first<=last && first!=std::string::npos) str=str.substr(first,last+1); } -std::string Tools::extension(const std::string&s){ +std::string Tools::extension(const std::string&s) { size_t n=s.find_last_of("."); std::string ext; - if(n!=std::string::npos && n+1<s.length() && n+5>=s.length()){ + if(n!=std::string::npos && n+1<s.length() && n+5>=s.length()) { ext=s.substr(n+1); if(ext.find("/")!=std::string::npos) ext=""; string base=s.substr(0,n); @@ -328,13 +328,13 @@ std::string Tools::extension(const std::string&s){ return ext; } -bool Tools::startWith(const std::string & full,const std::string &start){ +bool Tools::startWith(const std::string & full,const std::string &start) { return (full.substr(0,start.length())==start); } -bool Tools::findKeyword(const std::vector<std::string>&line,const std::string&key){ +bool Tools::findKeyword(const std::vector<std::string>&line,const std::string&key) { const std::string search(key+"="); - for(const auto & p : line){ + for(const auto & p : line) { if(startWith(p,search)) return true; } return false; diff --git a/src/tools/Tools.h b/src/tools/Tools.h index 27d894530..74ca0bec0 100644 --- a/src/tools/Tools.h +++ b/src/tools/Tools.h @@ -31,7 +31,7 @@ #include <algorithm> #include <sstream> -namespace PLMD{ +namespace PLMD { class IFile; @@ -49,7 +49,7 @@ const double pi(3.14159265358979323846264338327950288419716939937510582097494459 /// \ingroup TOOLBOX /// Empty class which just contains several (static) tools -class Tools{ +class Tools { /// class to convert a string to a generic type T template<class T> static bool convertToAny(const std::string & str,T &t); @@ -114,7 +114,7 @@ public: static bool findKeyword(const std::vector<std::string>&line,const std::string&key); /// Interpret atom ranges static void interpretRanges(std::vector<std::string>&); -/// Remove duplicates from a vector of type T +/// Remove duplicates from a vector of type T template <typename T> static void removeDuplicates(std::vector<T>& vec); /// interpret ":" syntax for labels @@ -127,7 +127,7 @@ public: /// E.g.: extension("pippo.xyz")="xyz". /// It only returns extensions with a length between 1 and 4 /// E.g.: extension("pippo.12345")="" whereas extenion("pippo.1234")="1234"; -/// It is also smart enough to detect "/", so that +/// It is also smart enough to detect "/", so that /// extension("pippo/.t")="" whereas extension("pippo/a.t")="t" static std::string extension(const std::string&); /// Fast int power @@ -138,7 +138,7 @@ public: }; template <class T> -bool Tools::parse(std::vector<std::string>&line,const std::string&key,T&val,int rep){ +bool Tools::parse(std::vector<std::string>&line,const std::string&key,T&val,int rep) { std::string s; if(!getKey(line,key+"=",s,rep)) return false; if(s.length()>0 && !convert(s,val))return false; @@ -146,17 +146,17 @@ bool Tools::parse(std::vector<std::string>&line,const std::string&key,T&val,int } template <class T> -bool Tools::parseVector(std::vector<std::string>&line,const std::string&key,std::vector<T>&val,int rep){ +bool Tools::parseVector(std::vector<std::string>&line,const std::string&key,std::vector<T>&val,int rep) { std::string s; if(!getKey(line,key+"=",s,rep)) return false; // if(s.length()==0) return true; val.clear(); std::vector<std::string> words=getWords(s,"\t\n ,"); - for(unsigned i=0;i<words.size();++i){ + for(unsigned i=0; i<words.size(); ++i) { T v; std::string s=words[i]; const std::string multi("@replicas:"); - if(rep>=0 && startWith(s,multi)){ + if(rep>=0 && startWith(s,multi)) { s=s.substr(multi.length(),s.length()); std::vector<std::string> words=getWords(s,"\t\n ,"); plumed_assert(rep<words.size()); @@ -171,14 +171,14 @@ bool Tools::parseVector(std::vector<std::string>&line,const std::string&key,std: template<typename T> void Tools::removeDuplicates(std::vector<T>& vec) { - std::sort(vec.begin(), vec.end()); - vec.erase(std::unique(vec.begin(), vec.end()), vec.end()); + std::sort(vec.begin(), vec.end()); + vec.erase(std::unique(vec.begin(), vec.end()), vec.end()); } inline -bool Tools::parseFlag(std::vector<std::string>&line,const std::string&key,bool&val){ - for(auto p=line.begin();p!=line.end();++p){ - if(key==*p){ +bool Tools::parseFlag(std::vector<std::string>&line,const std::string&key,bool&val) { + for(auto p=line.begin(); p!=line.end(); ++p) { + if(key==*p) { val=true; line.erase(p); return true; @@ -189,7 +189,7 @@ bool Tools::parseFlag(std::vector<std::string>&line,const std::string&key,bool&v /// beware: this brings any number into a pbc that ranges from -0.5 to 0.5 inline -double Tools::pbc(double x){ +double Tools::pbc(double x) { #ifdef __PLUMED_PBC_WHILE while (x>0.5) x-=1.0; while (x<-0.5) x+=1.0; @@ -207,29 +207,29 @@ double Tools::pbc(double x){ } template<typename T> -void Tools::convert(T i,std::string & str){ - std::ostringstream ostr; - ostr<<i; - str=ostr.str(); +void Tools::convert(T i,std::string & str) { + std::ostringstream ostr; + ostr<<i; + str=ostr.str(); } inline double Tools::fastpow(double base, int exp) { - if(exp<0){ - exp=-exp; - base=1.0/base; - } - double result = 1.0; - while (exp) - { - if (exp & 1) - result *= base; - exp >>= 1; - base *= base; - } + if(exp<0) { + exp=-exp; + base=1.0/base; + } + double result = 1.0; + while (exp) + { + if (exp & 1) + result *= base; + exp >>= 1; + base *= base; + } - return result; + return result; } } diff --git a/src/tools/Torsion.cpp b/src/tools/Torsion.cpp index d12498600..4464e1bd1 100644 --- a/src/tools/Torsion.cpp +++ b/src/tools/Torsion.cpp @@ -25,18 +25,18 @@ #include <cmath> #include <iostream> -namespace PLMD{ - -double Torsion::compute(const Vector& v1,const Vector& v2,const Vector& v3)const{ - const Vector nv2(v2*(1.0/v2.modulo())); - const Vector a(crossProduct(nv2,v1)); - const Vector b(crossProduct(v3,nv2)); - const double cosangle=dotProduct(a,b); - const double sinangle=dotProduct(crossProduct(a,b),nv2); - return std::atan2(-sinangle,cosangle); +namespace PLMD { + +double Torsion::compute(const Vector& v1,const Vector& v2,const Vector& v3)const { + const Vector nv2(v2*(1.0/v2.modulo())); + const Vector a(crossProduct(nv2,v1)); + const Vector b(crossProduct(v3,nv2)); + const double cosangle=dotProduct(a,b); + const double sinangle=dotProduct(crossProduct(a,b),nv2); + return std::atan2(-sinangle,cosangle); } -double Torsion::compute(const Vector& v1,const Vector& v2,const Vector& v3,Vector& d1,Vector& d2,Vector& d3)const{ +double Torsion::compute(const Vector& v1,const Vector& v2,const Vector& v3,Vector& d1,Vector& d2,Vector& d3)const { const double modv2(1./v2.modulo()); const Vector nv2(v2*modv2); diff --git a/src/tools/Torsion.h b/src/tools/Torsion.h index b8ac74041..b898a99cc 100644 --- a/src/tools/Torsion.h +++ b/src/tools/Torsion.h @@ -24,7 +24,7 @@ #include "Vector.h" -namespace PLMD{ +namespace PLMD { /// \ingroup TOOLBOX /// Class to compute torsional angles. @@ -36,7 +36,7 @@ namespace PLMD{ /// I know it is a bit misleading. If we really do not need to store "options" /// inside the Torsion class, we can remove it later and write compute as /// a static function. -class Torsion{ +class Torsion { // still empty, but may accomodate some options in the future public: /// Compute the angle between the projections of v1 and v3 on the plane orthogonal diff --git a/src/tools/Units.cpp b/src/tools/Units.cpp index 3bb5c8886..48737c9d0 100644 --- a/src/tools/Units.cpp +++ b/src/tools/Units.cpp @@ -24,7 +24,7 @@ using namespace std; -namespace PLMD{ +namespace PLMD { Units::Units(): energy(1.0), @@ -40,15 +40,15 @@ Units::Units(): { } -void Units::setEnergy(const std::string &s){ +void Units::setEnergy(const std::string &s) { energyString=s; - if(s=="kj/mol"){ + if(s=="kj/mol") { energy=1.0; - } else if(s=="kcal/mol"){ + } else if(s=="kcal/mol") { energy=4.184; - } else if(s=="j/mol"){ + } else if(s=="j/mol") { energy=0.001; - } else if(s=="eV"){ + } else if(s=="eV") { energy=96.48530749925792; } else { energy=-1.0; @@ -58,13 +58,13 @@ void Units::setEnergy(const std::string &s){ } } -void Units::setLength(const std::string &s){ +void Units::setLength(const std::string &s) { lengthString=s; - if(s=="nm"){ + if(s=="nm") { length=1.0; - } else if(s=="A"){ + } else if(s=="A") { length=0.1; - } else if(s=="um"){ + } else if(s=="um") { length=1000.0; } else { length=-1.0; @@ -74,13 +74,13 @@ void Units::setLength(const std::string &s){ } } -void Units::setTime(const std::string &s){ +void Units::setTime(const std::string &s) { timeString=s; - if(s=="ps"){ + if(s=="ps") { time=1.0; - } else if(s=="ns"){ + } else if(s=="ns") { time=1000.0; - } else if(s=="fs"){ + } else if(s=="fs") { time=0.001; } else { time=-1.0; @@ -90,9 +90,9 @@ void Units::setTime(const std::string &s){ } } -void Units::setCharge(const std::string &s){ +void Units::setCharge(const std::string &s) { chargeString=s; - if(s=="e"){ + if(s=="e") { charge=1.0; } else { charge=-1.0; @@ -102,9 +102,9 @@ void Units::setCharge(const std::string &s){ } } -void Units::setMass(const std::string &s){ +void Units::setMass(const std::string &s) { massString=s; - if(s=="amu"){ + if(s=="amu") { mass=1.0; } else { mass=-1.0; @@ -114,27 +114,27 @@ void Units::setMass(const std::string &s){ } } -void Units::setEnergy(const double s){ +void Units::setEnergy(const double s) { energyString=""; energy=s; } -void Units::setLength(const double s){ +void Units::setLength(const double s) { lengthString=""; length=s; } -void Units::setTime(const double s){ +void Units::setTime(const double s) { timeString=""; time=s; } -void Units::setCharge(const double s){ +void Units::setCharge(const double s) { chargeString=""; charge=s; } -void Units::setMass(const double s){ +void Units::setMass(const double s) { massString=""; mass=s; } diff --git a/src/tools/Units.h b/src/tools/Units.h index e7f5c6335..12074cc21 100644 --- a/src/tools/Units.h +++ b/src/tools/Units.h @@ -24,7 +24,7 @@ #include <string> -namespace PLMD{ +namespace PLMD { /** \ingroup TOOLBOX @@ -38,7 +38,7 @@ one can also use strings such as kcal/mol. */ -class Units{ +class Units { /// Units for energy, expressed in kj/mol (e.g. 4.184 means kcal/mol) double energy; std::string energyString; @@ -111,52 +111,52 @@ public: }; inline -const double & Units::getEnergy()const{ +const double & Units::getEnergy()const { return energy; } inline -const double & Units::getLength()const{ +const double & Units::getLength()const { return length; } inline -const double & Units::getTime()const{ +const double & Units::getTime()const { return time; } inline -const double & Units::getCharge()const{ +const double & Units::getCharge()const { return charge; } inline -const double & Units::getMass()const{ +const double & Units::getMass()const { return mass; } inline -const std::string & Units::getEnergyString()const{ +const std::string & Units::getEnergyString()const { return energyString; } inline -const std::string & Units::getLengthString()const{ +const std::string & Units::getLengthString()const { return lengthString; } inline -const std::string & Units::getTimeString()const{ +const std::string & Units::getTimeString()const { return timeString; } inline -const std::string & Units::getChargeString()const{ +const std::string & Units::getChargeString()const { return chargeString; } inline -const std::string & Units::getMassString()const{ +const std::string & Units::getMassString()const { return massString; } diff --git a/src/tools/Vector.cpp b/src/tools/Vector.cpp index f868a1aba..8f2883acb 100644 --- a/src/tools/Vector.cpp +++ b/src/tools/Vector.cpp @@ -23,18 +23,18 @@ #include "Exception.h" #include <cmath> -namespace PLMD{ +namespace PLMD { /// Small auxiliary class. /// I use it to test a few things that I am scary of and could introduce bugs. /// It checks at startup that Vector satifies some requirement so as to allow /// accessing a vector of tensors as a 3 times longer array of doubles. -static class VectorChecks{ +static class VectorChecks { public: - VectorChecks(){ + VectorChecks() { if( sizeof(VectorGeneric<2>)==2*sizeof(double) - && sizeof(VectorGeneric<3>)==3*sizeof(double) - && sizeof(VectorGeneric<4>)==4*sizeof(double)) return; + && sizeof(VectorGeneric<3>)==3*sizeof(double) + && sizeof(VectorGeneric<4>)==4*sizeof(double)) return; plumed_merror("sizeof(VectorGeneric<x>)!=x*sizeof(double). PLUMED cannot work properly in these conditions."); } } checks; diff --git a/src/tools/Vector.h b/src/tools/Vector.h index 8c3422c2f..133ff4a19 100644 --- a/src/tools/Vector.h +++ b/src/tools/Vector.h @@ -31,7 +31,7 @@ #endif -namespace PLMD{ +namespace PLMD { /** \ingroup TOOLBOX @@ -43,7 +43,7 @@ This class implements a vector of doubles with size fixed at compile time. It is useful for small fixed size objects (e.g. 3d vectors) as it does not waste space to store the vector size. Moreover, as the compiler knows the size, it can be completely -opimized inline. +opimized inline. All the methods are inlined for better optimization and all the loops are explicitly unrolled using PLMD::LoopUnroller class. Vector elements are initialized to zero by default. Notice that @@ -80,7 +80,7 @@ int main(){ template <unsigned n> -class VectorGeneric{ +class VectorGeneric { double d[n]; public: /// Create it with preassigned components. @@ -155,14 +155,14 @@ public: template<> inline -VectorGeneric<2>:: VectorGeneric(double x0,double x1){ +VectorGeneric<2>:: VectorGeneric(double x0,double x1) { d[0]=x0; d[1]=x1; } template<> inline -VectorGeneric<3>:: VectorGeneric(double x0,double x1,double x2){ +VectorGeneric<3>:: VectorGeneric(double x0,double x1,double x2) { d[0]=x0; d[1]=x1; d[2]=x2; @@ -170,7 +170,7 @@ VectorGeneric<3>:: VectorGeneric(double x0,double x1,double x2){ template<> inline -VectorGeneric<4>:: VectorGeneric(double x0,double x1,double x2,double x3){ +VectorGeneric<4>:: VectorGeneric(double x0,double x1,double x2,double x3) { d[0]=x0; d[1]=x1; d[2]=x2; @@ -178,17 +178,17 @@ VectorGeneric<4>:: VectorGeneric(double x0,double x1,double x2,double x3){ } template <unsigned n> -void VectorGeneric<n>::zero(){ +void VectorGeneric<n>::zero() { LoopUnroller<n>::_zero(d); } template <unsigned n> -VectorGeneric<n>::VectorGeneric(){ +VectorGeneric<n>::VectorGeneric() { LoopUnroller<n>::_zero(d); } template <unsigned n> -double & VectorGeneric<n>::operator[](unsigned i){ +double & VectorGeneric<n>::operator[](unsigned i) { #ifdef _GLIBCXX_DEBUG plumed_assert(i<n); #endif @@ -196,7 +196,7 @@ double & VectorGeneric<n>::operator[](unsigned i){ } template <unsigned n> -const double & VectorGeneric<n>::operator[](unsigned i)const{ +const double & VectorGeneric<n>::operator[](unsigned i)const { #ifdef _GLIBCXX_DEBUG plumed_assert(i<n); #endif @@ -204,7 +204,7 @@ const double & VectorGeneric<n>::operator[](unsigned i)const{ } template <unsigned n> -double & VectorGeneric<n>::operator()(unsigned i){ +double & VectorGeneric<n>::operator()(unsigned i) { #ifdef _GLIBCXX_DEBUG plumed_assert(i<n); #endif @@ -212,7 +212,7 @@ double & VectorGeneric<n>::operator()(unsigned i){ } template <unsigned n> -const double & VectorGeneric<n>::operator()(unsigned i)const{ +const double & VectorGeneric<n>::operator()(unsigned i)const { #ifdef _GLIBCXX_DEBUG plumed_assert(i<n); #endif @@ -220,110 +220,110 @@ const double & VectorGeneric<n>::operator()(unsigned i)const{ } template <unsigned n> -VectorGeneric<n>& VectorGeneric<n>::operator +=(const VectorGeneric<n>& b){ +VectorGeneric<n>& VectorGeneric<n>::operator +=(const VectorGeneric<n>& b) { LoopUnroller<n>::_add(d,b.d); return *this; } template <unsigned n> -VectorGeneric<n>& VectorGeneric<n>::operator -=(const VectorGeneric<n>& b){ +VectorGeneric<n>& VectorGeneric<n>::operator -=(const VectorGeneric<n>& b) { LoopUnroller<n>::_sub(d,b.d); return *this; } template <unsigned n> -VectorGeneric<n>& VectorGeneric<n>::operator *=(double s){ +VectorGeneric<n>& VectorGeneric<n>::operator *=(double s) { LoopUnroller<n>::_mul(d,s); return *this; } template <unsigned n> -VectorGeneric<n>& VectorGeneric<n>::operator /=(double s){ +VectorGeneric<n>& VectorGeneric<n>::operator /=(double s) { LoopUnroller<n>::_mul(d,1.0/s); return *this; } template <unsigned n> -VectorGeneric<n> VectorGeneric<n>::operator +()const{ +VectorGeneric<n> VectorGeneric<n>::operator +()const { return *this; } template <unsigned n> -VectorGeneric<n> VectorGeneric<n>::operator -()const{ +VectorGeneric<n> VectorGeneric<n>::operator -()const { VectorGeneric<n> r; LoopUnroller<n>::_neg(r.d,d); return r; } template <unsigned n> -VectorGeneric<n> operator+(const VectorGeneric<n>&v1,const VectorGeneric<n>&v2){ +VectorGeneric<n> operator+(const VectorGeneric<n>&v1,const VectorGeneric<n>&v2) { VectorGeneric<n> v(v1); return v+=v2; } template <unsigned n> -VectorGeneric<n> operator-(const VectorGeneric<n>&v1,const VectorGeneric<n>&v2){ +VectorGeneric<n> operator-(const VectorGeneric<n>&v1,const VectorGeneric<n>&v2) { VectorGeneric<n> v(v1); return v-=v2; } template <unsigned n> -VectorGeneric<n> operator*(double s,const VectorGeneric<n>&v){ +VectorGeneric<n> operator*(double s,const VectorGeneric<n>&v) { VectorGeneric<n> vv(v); return vv*=s; } template <unsigned n> -VectorGeneric<n> operator*(const VectorGeneric<n>&v,double s){ +VectorGeneric<n> operator*(const VectorGeneric<n>&v,double s) { return s*v; } template <unsigned n> -VectorGeneric<n> operator/(const VectorGeneric<n>&v,double s){ +VectorGeneric<n> operator/(const VectorGeneric<n>&v,double s) { return v*(1.0/s); } template <unsigned n> -VectorGeneric<n> delta(const VectorGeneric<n>&v1,const VectorGeneric<n>&v2){ +VectorGeneric<n> delta(const VectorGeneric<n>&v1,const VectorGeneric<n>&v2) { return v2-v1; } template <unsigned n> -double VectorGeneric<n>::modulo2()const{ +double VectorGeneric<n>::modulo2()const { return LoopUnroller<n>::_sum2(d); } template <unsigned n> -double dotProduct(const VectorGeneric<n>& v1,const VectorGeneric<n>& v2){ +double dotProduct(const VectorGeneric<n>& v1,const VectorGeneric<n>& v2) { return LoopUnroller<n>::_dot(v1.d,v2.d); } inline -VectorGeneric<3> crossProduct(const VectorGeneric<3>& v1,const VectorGeneric<3>& v2){ - return VectorGeneric<3>( - v1[1]*v2[2]-v1[2]*v2[1], - v1[2]*v2[0]-v1[0]*v2[2], - v1[0]*v2[1]-v1[1]*v2[0]); +VectorGeneric<3> crossProduct(const VectorGeneric<3>& v1,const VectorGeneric<3>& v2) { + return VectorGeneric<3>( + v1[1]*v2[2]-v1[2]*v2[1], + v1[2]*v2[0]-v1[0]*v2[2], + v1[0]*v2[1]-v1[1]*v2[0]); } template<unsigned n> -double VectorGeneric<n>::modulo()const{ +double VectorGeneric<n>::modulo()const { return sqrt(modulo2()); } template<unsigned n> -double modulo2(const VectorGeneric<n>&v){ +double modulo2(const VectorGeneric<n>&v) { return v.modulo2(); } template<unsigned n> -double modulo(const VectorGeneric<n>&v){ +double modulo(const VectorGeneric<n>&v) { return v.modulo(); } template<unsigned n> -std::ostream & operator<<(std::ostream &os, const VectorGeneric<n>& v){ - for(unsigned i=0;i<n-1;i++) os<<v(i)<<" "; +std::ostream & operator<<(std::ostream &os, const VectorGeneric<n>& v) { + for(unsigned i=0; i<n-1; i++) os<<v(i)<<" "; os<<v(n-1); return os; } diff --git a/src/vatom/ActionWithVirtualAtom.h b/src/vatom/ActionWithVirtualAtom.h index b21695971..d461218ab 100644 --- a/src/vatom/ActionWithVirtualAtom.h +++ b/src/vatom/ActionWithVirtualAtom.h @@ -22,11 +22,11 @@ #ifndef __PLUMED_vatom_ActionWithVirtualAtom_h #define __PLUMED_vatom_ActionWithVirtualAtom_h #include "core/ActionWithVirtualAtom.h" -namespace PLMD{ -namespace vatom{ +namespace PLMD { +namespace vatom { // core/ActionWithVirtualAtom.h is left in core as it might be used in other classes // With this trick, PLMD::ActionWithVirtualAtom is visible as PLMD::vatom::ActionWithVirtualAtom - using PLMD::ActionWithVirtualAtom; +using PLMD::ActionWithVirtualAtom; } } #endif diff --git a/src/vatom/COM.cpp b/src/vatom/COM.cpp index 8d41ea87a..65f69a403 100644 --- a/src/vatom/COM.cpp +++ b/src/vatom/COM.cpp @@ -26,8 +26,8 @@ using namespace std; -namespace PLMD{ -namespace vatom{ +namespace PLMD { +namespace vatom { //+PLUMEDOC VATOM COM /* @@ -39,12 +39,12 @@ an atom list through the label for the COM action that creates it. For arbitrary weights (e.g. geometric center) see \ref CENTER. -When running with periodic boundary conditions, the atoms should be +When running with periodic boundary conditions, the atoms should be in the proper periodic image. This is done automatically since PLUMED 2.2, by considering the ordered list of atoms and rebuilding PBCs with a procedure that is equivalent to that done in \ref WHOLEMOLECULES . Notice that rebuilding is local to this action. This is different from \ref WHOLEMOLECULES -which actually modifies the coordinates stored in PLUMED. +which actually modifies the coordinates stored in PLUMED. In case you want to recover the old behavior you should use the NOPBC flag. In that case you need to take care that atoms are in the correct @@ -78,7 +78,7 @@ public: PLUMED_REGISTER_ACTION(COM,"COM") -void COM::registerKeywords(Keywords& keys){ +void COM::registerKeywords(Keywords& keys) { ActionWithVirtualAtom::registerKeywords(keys); keys.addFlag("NOPBC",false,"ignore the periodic boundary conditions when calculating distances"); } @@ -94,9 +94,9 @@ COM::COM(const ActionOptions&ao): parseFlag("NOPBC",nopbc); checkRead(); log.printf(" of atoms"); - for(unsigned i=0;i<atoms.size();++i) log.printf(" %d",atoms[i].serial()); + for(unsigned i=0; i<atoms.size(); ++i) log.printf(" %d",atoms[i].serial()); log.printf("\n"); - if(!nopbc){ + if(!nopbc) { log<<" PBC will be ignored\n"; } else { log<<" broken molecules will be rebuilt assuming atoms are in the proper order\n"; @@ -104,20 +104,20 @@ COM::COM(const ActionOptions&ao): requestAtoms(atoms); } -void COM::calculate(){ +void COM::calculate() { Vector pos; if(!nopbc) makeWhole(); double mass(0.0); vector<Tensor> deriv(getNumberOfAtoms()); - for(unsigned i=0;i<getNumberOfAtoms();i++) mass+=getMass(i); - if( plumed.getAtoms().chargesWereSet() ){ - double charge(0.0); - for(unsigned i=0;i<getNumberOfAtoms();i++) charge+=getCharge(i); - setCharge(charge); + for(unsigned i=0; i<getNumberOfAtoms(); i++) mass+=getMass(i); + if( plumed.getAtoms().chargesWereSet() ) { + double charge(0.0); + for(unsigned i=0; i<getNumberOfAtoms(); i++) charge+=getCharge(i); + setCharge(charge); } else { - setCharge(0.0); + setCharge(0.0); } - for(unsigned i=0;i<getNumberOfAtoms();i++){ + for(unsigned i=0; i<getNumberOfAtoms(); i++) { pos+=(getMass(i)/mass)*getPosition(i); deriv[i]=(getMass(i)/mass)*Tensor::identity(); } diff --git a/src/vatom/Center.cpp b/src/vatom/Center.cpp index 6118d8274..d29fca69f 100644 --- a/src/vatom/Center.cpp +++ b/src/vatom/Center.cpp @@ -26,8 +26,8 @@ using namespace std; -namespace PLMD{ -namespace vatom{ +namespace PLMD { +namespace vatom { //+PLUMEDOC VATOM CENTER /* @@ -40,12 +40,12 @@ Notice that the generated virtual atom has charge equal to the sum of the charges and mass equal to the sum of the masses. If used with the MASS flag, then it provides a result identical to \ref COM. -When running with periodic boundary conditions, the atoms should be +When running with periodic boundary conditions, the atoms should be in the proper periodic image. This is done automatically since PLUMED 2.2, by considering the ordered list of atoms and rebuilding PBCs with a procedure that is equivalent to that done in \ref WHOLEMOLECULES . Notice that rebuilding is local to this action. This is different from \ref WHOLEMOLECULES -which actually modifies the coordinates stored in PLUMED. +which actually modifies the coordinates stored in PLUMED. In case you want to recover the old behavior you should use the NOPBC flag. In that case you need to take care that atoms are in the correct @@ -88,7 +88,7 @@ public: PLUMED_REGISTER_ACTION(Center,"CENTER") -void Center::registerKeywords(Keywords& keys){ +void Center::registerKeywords(Keywords& keys) { ActionWithVirtualAtom::registerKeywords(keys); keys.add("optional","WEIGHTS","Center is computed as a weighted average."); keys.addFlag("NOPBC",false,"ignore the periodic boundary conditions when calculating distances"); @@ -109,21 +109,21 @@ Center::Center(const ActionOptions&ao): parseFlag("NOPBC",nopbc); checkRead(); log.printf(" of atoms"); - for(unsigned i=0;i<atoms.size();++i) log.printf(" %d",atoms[i].serial()); - if(weight_mass){ + for(unsigned i=0; i<atoms.size(); ++i) log.printf(" %d",atoms[i].serial()); + if(weight_mass) { log<<" mass weighted\n"; if(weights.size()!=0) error("WEIGHTS and MASS keywords should not be used simultaneously"); } else { if( weights.size()==0) { weights.resize( atoms.size() ); - for(unsigned i=0;i<atoms.size();i++) weights[i] = 1.; + for(unsigned i=0; i<atoms.size(); i++) weights[i] = 1.; } log<<" with weights"; if( weights.size()!=atoms.size() ) error("number of elements in weight vector does not match the number of atoms"); - for(unsigned i=0;i<weights.size();++i) log.printf(" %f",weights[i]); + for(unsigned i=0; i<weights.size(); ++i) log.printf(" %f",weights[i]); log.printf("\n"); } - if(!nopbc){ + if(!nopbc) { log<<" PBC will be ignored\n"; } else { log<<" broken molecules will be rebuilt assuming atoms are in the proper order\n"; @@ -131,22 +131,22 @@ Center::Center(const ActionOptions&ao): requestAtoms(atoms); } -void Center::calculate(){ +void Center::calculate() { Vector pos; double mass(0.0); if(!nopbc) makeWhole(); vector<Tensor> deriv(getNumberOfAtoms()); - for(unsigned i=0;i<getNumberOfAtoms();i++) mass+=getMass(i); - if( plumed.getAtoms().chargesWereSet() ){ - double charge(0.0); - for(unsigned i=0;i<getNumberOfAtoms();i++) charge+=getCharge(i); - setCharge(charge); + for(unsigned i=0; i<getNumberOfAtoms(); i++) mass+=getMass(i); + if( plumed.getAtoms().chargesWereSet() ) { + double charge(0.0); + for(unsigned i=0; i<getNumberOfAtoms(); i++) charge+=getCharge(i); + setCharge(charge); } else { - setCharge(0.0); + setCharge(0.0); } double wtot=0.0; - for(unsigned i=0;i<weights.size();i++) wtot+=weights[i]; - for(unsigned i=0;i<getNumberOfAtoms();i++){ + for(unsigned i=0; i<weights.size(); i++) wtot+=weights[i]; + for(unsigned i=0; i<getNumberOfAtoms(); i++) { double w=0; if(weight_mass) w=getMass(i)/mass; else w=weights[i]/wtot; diff --git a/src/vatom/FixedAtom.cpp b/src/vatom/FixedAtom.cpp index 60efa8d3b..ccf7eb52c 100644 --- a/src/vatom/FixedAtom.cpp +++ b/src/vatom/FixedAtom.cpp @@ -26,8 +26,8 @@ using namespace std; -namespace PLMD{ -namespace vatom{ +namespace PLMD { +namespace vatom { //+PLUMEDOC VATOM FIXEDATOM /* @@ -89,7 +89,7 @@ public: PLUMED_REGISTER_ACTION(FixedAtom,"FIXEDATOM") -void FixedAtom::registerKeywords(Keywords& keys){ +void FixedAtom::registerKeywords(Keywords& keys) { ActionWithVirtualAtom::registerKeywords(keys); keys.add("compulsory","AT","coordinates of the virtual atom"); keys.add("compulsory","SET_MASS","1","mass of the virtual atom"); @@ -123,9 +123,9 @@ FixedAtom::FixedAtom(const ActionOptions&ao): if(scaled_components) log<<" position is in scaled components\n"; } -void FixedAtom::calculate(){ +void FixedAtom::calculate() { vector<Tensor> deriv(getNumberOfAtoms()); - if(scaled_components){ + if(scaled_components) { setPosition(getPbc().scaledToReal(coord)); } else { setPosition(coord); diff --git a/src/vatom/Ghost.cpp b/src/vatom/Ghost.cpp index e14f6db7a..fcd789377 100644 --- a/src/vatom/Ghost.cpp +++ b/src/vatom/Ghost.cpp @@ -26,13 +26,13 @@ using namespace std; -namespace PLMD{ -namespace vatom{ +namespace PLMD { +namespace vatom { -//+PLUMEDOC VATOM GHOST +//+PLUMEDOC VATOM GHOST /* Calculate the absolute position of a ghost atom with fixed coordinates -in the local reference frame formed by three atoms. +in the local reference frame formed by three atoms. The computed ghost atom is stored as a virtual atom that can be accessed in an atom list through the the label for the GHOST action that creates it. @@ -63,7 +63,7 @@ public: PLUMED_REGISTER_ACTION(Ghost,"GHOST") -void Ghost::registerKeywords(Keywords& keys){ +void Ghost::registerKeywords(Keywords& keys) { ActionWithVirtualAtom::registerKeywords(keys); keys.add("atoms","COORDINATES","coordinates of the ghost atom in the local reference frame"); } @@ -81,35 +81,35 @@ Ghost::Ghost(const ActionOptions&ao): checkRead(); log.printf(" of atoms"); - for(unsigned i=0;i<atoms.size();++i) log.printf(" %d",atoms[i].serial()); + for(unsigned i=0; i<atoms.size(); ++i) log.printf(" %d",atoms[i].serial()); log.printf("\n"); requestAtoms(atoms); } -void Ghost::calculate(){ +void Ghost::calculate() { Vector pos; vector<Tensor> deriv(getNumberOfAtoms()); vector<Vector> n; -// first versor +// first versor Vector n01 = delta(getPosition(0), getPosition(1)); n.push_back(n01/n01.modulo()); // auxiliary vector Vector n02 = delta(getPosition(0), getPosition(2)); -// second versor +// second versor Vector n03 = crossProduct(n[0],n02); double n03_norm = n03.modulo(); n.push_back(n03/n03_norm); -// third versor +// third versor n.push_back(crossProduct(n[0],n[1])); // origin of the reference system pos = getPosition(0); - for(unsigned i=0;i<3;++i){ + for(unsigned i=0; i<3; ++i) { pos += coord[i] * n[i]; } @@ -117,7 +117,7 @@ void Ghost::calculate(){ setMass(1.0); setCharge(0.0); -// some useful tensors for derivatives +// some useful tensors for derivatives Tensor dn0d0 = (-Tensor::identity()+Tensor(n[0],n[0]))/n01.modulo(); Tensor dn0d1 = (+Tensor::identity()-Tensor(n[0],n[0]))/n01.modulo(); Tensor dn02d0 = -Tensor::identity(); @@ -125,50 +125,50 @@ void Ghost::calculate(){ // derivative of n1 = n0 x n02 Tensor dn1d0, dn1d1, dn1d2; - Vector aux0, aux1, aux2; + Vector aux0, aux1, aux2; - for(unsigned j=0;j<3;++j){ + for(unsigned j=0; j<3; ++j) { // derivative of n0 x n02 with respect to point 0, coordinate j - Vector tmp00 = Vector( dn0d0(j,0), dn0d0(j,1), dn0d0(j,2)); - Vector tmp020 = Vector(dn02d0(j,0), dn02d0(j,1), dn02d0(j,2)); - Vector tmp0 = crossProduct(tmp00,n02) + crossProduct(n[0],tmp020); - aux0[j] = dotProduct(tmp0,n[1]); + Vector tmp00 = Vector( dn0d0(j,0), dn0d0(j,1), dn0d0(j,2)); + Vector tmp020 = Vector(dn02d0(j,0), dn02d0(j,1), dn02d0(j,2)); + Vector tmp0 = crossProduct(tmp00,n02) + crossProduct(n[0],tmp020); + aux0[j] = dotProduct(tmp0,n[1]); // derivative of n0 x n02 with respect to point 1, coordinate j - Vector tmp01 = Vector( dn0d1(j,0), dn0d1(j,1), dn0d1(j,2)); - Vector tmp1 = crossProduct(tmp01,n02); - aux1[j] = dotProduct(tmp1,n[1]); + Vector tmp01 = Vector( dn0d1(j,0), dn0d1(j,1), dn0d1(j,2)); + Vector tmp1 = crossProduct(tmp01,n02); + aux1[j] = dotProduct(tmp1,n[1]); // derivative of n0 x n02 with respect to point 2, coordinate j - Vector tmp022 = Vector(dn02d2(j,0), dn02d2(j,1), dn02d2(j,2)); - Vector tmp2 = crossProduct(n[0],tmp022); - aux2[j] = dotProduct(tmp2,n[1]); + Vector tmp022 = Vector(dn02d2(j,0), dn02d2(j,1), dn02d2(j,2)); + Vector tmp2 = crossProduct(n[0],tmp022); + aux2[j] = dotProduct(tmp2,n[1]); // derivative of n1 = (n0 x n02) / || (n0 x n02) || - for(unsigned i=0;i<3;++i) { - dn1d0(j,i) = ( tmp0[i] - aux0[j] * n[1][i] ) / n03_norm; - dn1d1(j,i) = ( tmp1[i] - aux1[j] * n[1][i] ) / n03_norm; - dn1d2(j,i) = ( tmp2[i] - aux2[j] * n[1][i] ) / n03_norm; - } + for(unsigned i=0; i<3; ++i) { + dn1d0(j,i) = ( tmp0[i] - aux0[j] * n[1][i] ) / n03_norm; + dn1d1(j,i) = ( tmp1[i] - aux1[j] * n[1][i] ) / n03_norm; + dn1d2(j,i) = ( tmp2[i] - aux2[j] * n[1][i] ) / n03_norm; + } } // Derivative of the last versor n2 = n0 x n1 = ( n0( n0 n02 ) - n02 ) / || n0 x n02 || // Scalar product and derivatives - double n0_n02 = dotProduct(n[0],n02); + double n0_n02 = dotProduct(n[0],n02); Vector dn0_n02d0, dn0_n02d1, dn0_n02d2; - for(unsigned j=0;j<3;++j){ - for(unsigned i=0;i<3;++i){ - dn0_n02d0[j] += dn0d0(j,i)*n02[i] + n[0][i]*dn02d0(j,i); - dn0_n02d1[j] += dn0d1(j,i)*n02[i]; - dn0_n02d2[j] += n[0][i]*dn02d2(j,i); - } + for(unsigned j=0; j<3; ++j) { + for(unsigned i=0; i<3; ++i) { + dn0_n02d0[j] += dn0d0(j,i)*n02[i] + n[0][i]*dn02d0(j,i); + dn0_n02d1[j] += dn0d1(j,i)*n02[i]; + dn0_n02d2[j] += n[0][i]*dn02d2(j,i); + } } Tensor dn2d0, dn2d1, dn2d2; - for(unsigned j=0;j<3;++j){ - for(unsigned i=0;i<3;++i){ - dn2d0(j,i) = ( dn0d0(j,i) * n0_n02 + n[0][i] * dn0_n02d0[j] - dn02d0(j,i) - ( n[0][i] * n0_n02 - n02[i] ) * aux0[j] / n03_norm ) / n03_norm; - dn2d1(j,i) = ( dn0d1(j,i) * n0_n02 + n[0][i] * dn0_n02d1[j] - ( n[0][i] * n0_n02 - n02[i] ) * aux1[j] / n03_norm ) / n03_norm; - dn2d2(j,i) = ( n[0][i] * dn0_n02d2[j] - dn02d2(j,i) - ( n[0][i] * n0_n02 - n02[i] ) * aux2[j] / n03_norm ) / n03_norm; - } + for(unsigned j=0; j<3; ++j) { + for(unsigned i=0; i<3; ++i) { + dn2d0(j,i) = ( dn0d0(j,i) * n0_n02 + n[0][i] * dn0_n02d0[j] - dn02d0(j,i) - ( n[0][i] * n0_n02 - n02[i] ) * aux0[j] / n03_norm ) / n03_norm; + dn2d1(j,i) = ( dn0d1(j,i) * n0_n02 + n[0][i] * dn0_n02d1[j] - ( n[0][i] * n0_n02 - n02[i] ) * aux1[j] / n03_norm ) / n03_norm; + dn2d2(j,i) = ( n[0][i] * dn0_n02d2[j] - dn02d2(j,i) - ( n[0][i] * n0_n02 - n02[i] ) * aux2[j] / n03_norm ) / n03_norm; + } } // Finally, the derivative tensor diff --git a/src/vesselbase/ActionWithAveraging.cpp b/src/vesselbase/ActionWithAveraging.cpp index e6111a769..a470f6f5f 100644 --- a/src/vesselbase/ActionWithAveraging.cpp +++ b/src/vesselbase/ActionWithAveraging.cpp @@ -26,104 +26,104 @@ namespace PLMD { namespace vesselbase { -void ActionWithAveraging::registerKeywords( Keywords& keys ){ - Action::registerKeywords( keys ); ActionPilot::registerKeywords( keys ); ActionAtomistic::registerKeywords( keys ); +void ActionWithAveraging::registerKeywords( Keywords& keys ) { + Action::registerKeywords( keys ); ActionPilot::registerKeywords( keys ); ActionAtomistic::registerKeywords( keys ); ActionWithArguments::registerKeywords( keys ); ActionWithValue::registerKeywords( keys ); ActionWithVessel::registerKeywords( keys ); keys.add("compulsory","STRIDE","1","the frequency with which the data should be collected and added to the quantity being averaged"); keys.add("compulsory","CLEAR","0","the frequency with which to clear all the accumulated data. The default value " - "of 0 implies that all the data will be used and that the grid will never be cleared"); + "of 0 implies that all the data will be used and that the grid will never be cleared"); keys.add("optional","LOGWEIGHTS","list of actions that calculates log weights that should be used to weight configurations when calculating averages"); keys.addFlag("UNORMALIZED",false,"output the unaveraged quantity/quantities."); keys.remove("NUMERICAL_DERIVATIVES"); } ActionWithAveraging::ActionWithAveraging( const ActionOptions& ao ): -Action(ao), -ActionPilot(ao), -ActionAtomistic(ao), -ActionWithArguments(ao), -ActionWithValue(ao), -ActionWithVessel(ao), -myaverage(NULL), -useRunAllTasks(false), -clearstride(0), -lweight(0),cweight(0) + Action(ao), + ActionPilot(ao), + ActionAtomistic(ao), + ActionWithArguments(ao), + ActionWithValue(ao), + ActionWithVessel(ao), + myaverage(NULL), + useRunAllTasks(false), + clearstride(0), + lweight(0),cweight(0) { - if( keywords.exists("CLEAR") ){ - parse("CLEAR",clearstride); - if( clearstride>0 ){ - if( clearstride%getStride()!=0 ) error("CLEAR parameter must be a multiple of STRIDE"); - log.printf(" clearing grid every %u steps \n",clearstride); - } + if( keywords.exists("CLEAR") ) { + parse("CLEAR",clearstride); + if( clearstride>0 ) { + if( clearstride%getStride()!=0 ) error("CLEAR parameter must be a multiple of STRIDE"); + log.printf(" clearing grid every %u steps \n",clearstride); + } } - if( keywords.exists("LOGWEIGHTS") ){ - std::vector<std::string> wwstr; parseVector("LOGWEIGHTS",wwstr); - if( wwstr.size()>0 ) log.printf(" reweighting using weights from "); - std::vector<Value*> arg( getArguments() ); - for(unsigned i=0;i<wwstr.size();++i){ - ActionWithValue* val = plumed.getActionSet().selectWithLabel<ActionWithValue*>(wwstr[i]); - if( !val ) error("could not find value named"); - weights.push_back( val->copyOutput(val->getLabel()) ); - arg.push_back( val->copyOutput(val->getLabel()) ); - log.printf("%s ",wwstr[i].c_str() ); - } - if( wwstr.size()>0 ) log.printf("\n"); - else log.printf(" weights are all equal to one\n"); - requestArguments( arg ); + if( keywords.exists("LOGWEIGHTS") ) { + std::vector<std::string> wwstr; parseVector("LOGWEIGHTS",wwstr); + if( wwstr.size()>0 ) log.printf(" reweighting using weights from "); + std::vector<Value*> arg( getArguments() ); + for(unsigned i=0; i<wwstr.size(); ++i) { + ActionWithValue* val = plumed.getActionSet().selectWithLabel<ActionWithValue*>(wwstr[i]); + if( !val ) error("could not find value named"); + weights.push_back( val->copyOutput(val->getLabel()) ); + arg.push_back( val->copyOutput(val->getLabel()) ); + log.printf("%s ",wwstr[i].c_str() ); + } + if( wwstr.size()>0 ) log.printf("\n"); + else log.printf(" weights are all equal to one\n"); + requestArguments( arg ); } if( keywords.exists("UNORMALIZED") ) parseFlag("UNORMALIZED",unormalised); } -void ActionWithAveraging::setAveragingAction( AveragingVessel* av_vessel, const bool& usetasks ){ - myaverage=av_vessel; addVessel( myaverage ); +void ActionWithAveraging::setAveragingAction( AveragingVessel* av_vessel, const bool& usetasks ) { + myaverage=av_vessel; addVessel( myaverage ); useRunAllTasks=usetasks; resizeFunctions(); } -void ActionWithAveraging::lockRequests(){ +void ActionWithAveraging::lockRequests() { ActionAtomistic::lockRequests(); ActionWithArguments::lockRequests(); } -void ActionWithAveraging::unlockRequests(){ +void ActionWithAveraging::unlockRequests() { ActionAtomistic::unlockRequests(); ActionWithArguments::unlockRequests(); } -void ActionWithAveraging::calculateNumericalDerivatives(PLMD::ActionWithValue*){ +void ActionWithAveraging::calculateNumericalDerivatives(PLMD::ActionWithValue*) { error("not possible to compute numerical derivatives for this action"); } -void ActionWithAveraging::update(){ +void ActionWithAveraging::update() { if( (clearstride!=1 && getStep()==0) || !onStep() ) return; // Clear if it is time to reset - if( myaverage ){ - if( myaverage->wasreset() ) clearAverage(); + if( myaverage ) { + if( myaverage->wasreset() ) clearAverage(); } // Calculate the weight for all reweighting - if ( weights.size()>0 ){ - double sum=0; for(unsigned i=0;i<weights.size();++i) sum+=weights[i]->get(); - lweight=sum; cweight = exp( sum ); + if ( weights.size()>0 ) { + double sum=0; for(unsigned i=0; i<weights.size(); ++i) sum+=weights[i]->get(); + lweight=sum; cweight = exp( sum ); } else { - lweight=0; cweight=1.0; + lweight=0; cweight=1.0; } // Prepare to do the averaging prepareForAveraging(); // Run all the tasks (if required - if( useRunAllTasks ) runAllTasks(); + if( useRunAllTasks ) runAllTasks(); // This the averaging if it is not done using task list else performOperations( true ); - // Update the norm + // Update the norm if( myaverage ) myaverage->setNorm( cweight + myaverage->getNorm() ); // Finish the averaging finishAveraging(); // By resetting here we are ensuring that the grid will be cleared at the start of the next step - if( myaverage ){ - if( getStride()==0 || (clearstride>0 && getStep()%clearstride==0) ) myaverage->reset(); + if( myaverage ) { + if( getStride()==0 || (clearstride>0 && getStep()%clearstride==0) ) myaverage->reset(); } } -void ActionWithAveraging::clearAverage(){ plumed_assert( myaverage->wasreset() ); myaverage->clear(); } +void ActionWithAveraging::clearAverage() { plumed_assert( myaverage->wasreset() ); myaverage->clear(); } -void ActionWithAveraging::performOperations( const bool& from_update ){ plumed_error(); } +void ActionWithAveraging::performOperations( const bool& from_update ) { plumed_error(); } } diff --git a/src/vesselbase/ActionWithAveraging.h b/src/vesselbase/ActionWithAveraging.h index fe33827e7..62b5642fb 100644 --- a/src/vesselbase/ActionWithAveraging.h +++ b/src/vesselbase/ActionWithAveraging.h @@ -35,8 +35,8 @@ namespace vesselbase { /** \ingroup INHERIT -This abstract base class should be used if you are writing some method that calculates an "average" from a set of -trajectory frames. Notice that we use the word average very broadly here and state that even dimensionality +This abstract base class should be used if you are writing some method that calculates an "average" from a set of +trajectory frames. Notice that we use the word average very broadly here and state that even dimensionality reduction algorithms calculate an "average." In other words, what we mean by average is that the method is going to take in data from each trajectory frame and only calculate the final quantity once a certain amount of data has been collected. @@ -49,7 +49,7 @@ class ActionWithAveraging : public ActionWithValue, public ActionWithVessel { -friend class AveragingVessel; + friend class AveragingVessel; private: /// The vessel which is used to compute averages AveragingVessel* myaverage; @@ -74,19 +74,19 @@ public: void lockRequests(); void unlockRequests(); void calculateNumericalDerivatives(PLMD::ActionWithValue*); - virtual unsigned getNumberOfDerivatives(){ return 0; } + virtual unsigned getNumberOfDerivatives() { return 0; } unsigned getNumberOfArguments() const ; /// Overwrite ActionWithArguments getArguments() so that we don't return the bias - std::vector<Value*> getArguments(); + std::vector<Value*> getArguments(); void update(); /// This does the clearing of the action virtual void clearAverage(); /// This is done before the averaging comences - virtual void prepareForAveraging(){} + virtual void prepareForAveraging() {} /// This does the averaging operation virtual void performOperations( const bool& from_update ); /// This is done once the averaging is finished - virtual void finishAveraging(){} + virtual void finishAveraging() {} }; inline @@ -95,9 +95,9 @@ unsigned ActionWithAveraging::getNumberOfArguments() const { } inline -std::vector<Value*> ActionWithAveraging::getArguments(){ +std::vector<Value*> ActionWithAveraging::getArguments() { std::vector<Value*> arg_vals( ActionWithArguments::getArguments() ); - for(unsigned i=0;i<weights.size();++i) arg_vals.erase(arg_vals.end()-1); + for(unsigned i=0; i<weights.size(); ++i) arg_vals.erase(arg_vals.end()-1); return arg_vals; } diff --git a/src/vesselbase/ActionWithInputVessel.cpp b/src/vesselbase/ActionWithInputVessel.cpp index e8d0df08f..b75c1f4a0 100644 --- a/src/vesselbase/ActionWithInputVessel.cpp +++ b/src/vesselbase/ActionWithInputVessel.cpp @@ -28,10 +28,10 @@ namespace PLMD { namespace vesselbase { -void ActionWithInputVessel::registerKeywords(Keywords& keys){ +void ActionWithInputVessel::registerKeywords(Keywords& keys) { keys.add("compulsory","DATA","certain actions in plumed work by calculating a list of variables and summing over them. " - "This particular action can be used to calculate functions of these base variables or prints " - "them to a file. This keyword thus takes the label of one of those such variables as input."); + "This particular action can be used to calculate functions of these base variables or prints " + "them to a file. This keyword thus takes the label of one of those such variables as input."); keys.reserve("compulsory","GRID","the action that creates the input grid you would like to use"); } @@ -42,46 +42,46 @@ ActionWithInputVessel::ActionWithInputVessel(const ActionOptions&ao): { } -void ActionWithInputVessel::readArgument( const std::string& type ){ - std::string mlab; +void ActionWithInputVessel::readArgument( const std::string& type ) { + std::string mlab; if( keywords.exists("DATA") && type!="grid" ) parse("DATA",mlab); ActionWithVessel* mves= plumed.getActionSet().selectWithLabel<ActionWithVessel*>(mlab); if(!mves) error("action labelled " + mlab + " does not exist or does not have vessels"); addDependency(mves); ActionWithValue* aval=dynamic_cast<ActionWithValue*>( this ); - if(aval){ - if( aval->checkNumericalDerivatives() ){ - ActionWithValue* aval2=dynamic_cast<ActionWithValue*>( mves ); - plumed_assert( aval2 ); aval2->useNumericalDerivatives(); - } + if(aval) { + if( aval->checkNumericalDerivatives() ) { + ActionWithValue* aval2=dynamic_cast<ActionWithValue*>( mves ); + plumed_assert( aval2 ); aval2->useNumericalDerivatives(); + } } - if( type=="bridge" ){ - ActionWithVessel* aves=dynamic_cast<ActionWithVessel*>( this ); - plumed_assert(aves); myBridgeVessel = mves->addBridgingVessel( aves ); - arguments = dynamic_cast<Vessel*>( myBridgeVessel ); - } else if( type=="store" ){ - arguments = dynamic_cast<Vessel*>( mves->buildDataStashes( NULL ) ); + if( type=="bridge" ) { + ActionWithVessel* aves=dynamic_cast<ActionWithVessel*>( this ); + plumed_assert(aves); myBridgeVessel = mves->addBridgingVessel( aves ); + arguments = dynamic_cast<Vessel*>( myBridgeVessel ); + } else if( type=="store" ) { + arguments = dynamic_cast<Vessel*>( mves->buildDataStashes( NULL ) ); } else { - plumed_error(); + plumed_error(); } } -void ActionWithInputVessel::calculateNumericalDerivatives( ActionWithValue* a ){ - if(!a){ +void ActionWithInputVessel::calculateNumericalDerivatives( ActionWithValue* a ) { + if(!a) { a=dynamic_cast<ActionWithValue*>(this); plumed_massert(a,"cannot compute numerical derivatives for an action without values"); } - if( myBridgeVessel ){ - myBridgeVessel->completeNumericalDerivatives(); + if( myBridgeVessel ) { + myBridgeVessel->completeNumericalDerivatives(); } else { - error("numerical derivatives are not implemented"); + error("numerical derivatives are not implemented"); } } -void ActionWithInputVessel::applyBridgeForces( const std::vector<double>& bb ){ - plumed_dbg_assert( myBridgeVessel ); addBridgeForces( bb ); +void ActionWithInputVessel::applyBridgeForces( const std::vector<double>& bb ) { + plumed_dbg_assert( myBridgeVessel ); addBridgeForces( bb ); } } diff --git a/src/vesselbase/ActionWithInputVessel.h b/src/vesselbase/ActionWithInputVessel.h index ac278768d..09d888f45 100644 --- a/src/vesselbase/ActionWithInputVessel.h +++ b/src/vesselbase/ActionWithInputVessel.h @@ -48,19 +48,19 @@ public: /// Registers the list of keywords static void registerKeywords( Keywords& keys ); explicit ActionWithInputVessel(const ActionOptions&); - virtual ~ActionWithInputVessel(){} + virtual ~ActionWithInputVessel() {} /// Calculate the numerical derivatives -/// N.B. only pass an ActionWithValue to this routine if you know exactly what you +/// N.B. only pass an ActionWithValue to this routine if you know exactly what you /// are doing. The default will be correct for the vast majority of cases virtual void calculateNumericalDerivatives( ActionWithValue* a=NULL ); /// Apply forces from the bridge void applyBridgeForces( const std::vector<double>& bb ); /// Apply forces from the bridge - virtual void addBridgeForces( const std::vector<double>& bb ){} + virtual void addBridgeForces( const std::vector<double>& bb ) {} }; inline -Vessel* ActionWithInputVessel::getPntrToArgument(){ +Vessel* ActionWithInputVessel::getPntrToArgument() { return arguments; } diff --git a/src/vesselbase/ActionWithVessel.cpp b/src/vesselbase/ActionWithVessel.cpp index 02eb060f0..ebbe511a4 100644 --- a/src/vesselbase/ActionWithVessel.cpp +++ b/src/vesselbase/ActionWithVessel.cpp @@ -32,16 +32,16 @@ #include "tools/Stopwatch.h" using namespace std; -namespace PLMD{ -namespace vesselbase{ +namespace PLMD { +namespace vesselbase { -void ActionWithVessel::registerKeywords(Keywords& keys){ +void ActionWithVessel::registerKeywords(Keywords& keys) { keys.add("hidden","TOL","this keyword can be used to speed up your calculation. When accumulating sums in which the individual " - "terms are numbers inbetween zero and one it is assumed that terms less than a certain tolerance " - "make only a small contribution to the sum. They can thus be safely ignored as can the the derivatives " - "wrt these small quantities."); + "terms are numbers inbetween zero and one it is assumed that terms less than a certain tolerance " + "make only a small contribution to the sum. They can thus be safely ignored as can the the derivatives " + "wrt these small quantities."); keys.add("hidden","MAXDERIVATIVES","The maximum number of derivatives that can be used when storing data. This controls when " - "we have to start using lowmem"); + "we have to start using lowmem"); keys.addFlag("SERIAL",false,"do the calculation in serial. Do not parallelize"); keys.addFlag("LOWMEM",false,"lower the memory requirements"); keys.addFlag("TIMINGS",false,"output information on the timings of the various parts of the calculation"); @@ -67,77 +67,77 @@ ActionWithVessel::ActionWithVessel(const ActionOptions&ao): if( keywords.exists("SERIAL") ) parseFlag("SERIAL",serial); else serial=true; if(serial)log.printf(" doing calculation in serial\n"); - if( keywords.exists("LOWMEM") ){ - plumed_assert( !keywords.exists("HIGHMEM") ); - parseFlag("LOWMEM",lowmem); - if(lowmem){ - log.printf(" lowering memory requirements\n"); - dertime_can_be_off=true; - } - } - if( keywords.exists("HIGHMEM") ){ - plumed_assert( !keywords.exists("LOWMEM") ); - bool highmem; parseFlag("HIGHMEM",highmem); - lowmem=!highmem; - if(!lowmem) log.printf(" increasing the memory requirements\n"); + if( keywords.exists("LOWMEM") ) { + plumed_assert( !keywords.exists("HIGHMEM") ); + parseFlag("LOWMEM",lowmem); + if(lowmem) { + log.printf(" lowering memory requirements\n"); + dertime_can_be_off=true; + } + } + if( keywords.exists("HIGHMEM") ) { + plumed_assert( !keywords.exists("LOWMEM") ); + bool highmem; parseFlag("HIGHMEM",highmem); + lowmem=!highmem; + if(!lowmem) log.printf(" increasing the memory requirements\n"); } - tolerance=nl_tolerance=epsilon; + tolerance=nl_tolerance=epsilon; if( keywords.exists("TOL") ) parse("TOL",tolerance); - if( tolerance>epsilon){ - log.printf(" Ignoring contributions less than %f \n",tolerance); + if( tolerance>epsilon) { + log.printf(" Ignoring contributions less than %f \n",tolerance); } parseFlag("TIMINGS",timers); stopwatch.start(); stopwatch.pause(); } -ActionWithVessel::~ActionWithVessel(){ - for(unsigned i=0;i<functions.size();++i) delete functions[i]; +ActionWithVessel::~ActionWithVessel() { + for(unsigned i=0; i<functions.size(); ++i) delete functions[i]; stopwatch.start(); stopwatch.stop(); - if(timers){ - log.printf("timings for action %s with label %s \n", getName().c_str(), getLabel().c_str() ); - log<<stopwatch; + if(timers) { + log.printf("timings for action %s with label %s \n", getName().c_str(), getLabel().c_str() ); + log<<stopwatch; } delete &stopwatch; } -void ActionWithVessel::addVessel( const std::string& name, const std::string& input, const int numlab ){ +void ActionWithVessel::addVessel( const std::string& name, const std::string& input, const int numlab ) { VesselOptions da(name,"",numlab,input,this); Vessel* vv=vesselRegister().create(name,da); FunctionVessel* fv=dynamic_cast<FunctionVessel*>(vv); - if( fv ){ - std::string mylabel=Vessel::transformName( name ); - plumed_massert( keywords.outputComponentExists(mylabel,false), "a description of the value calculated by vessel " + name + " has not been added to the manual"); - } + if( fv ) { + std::string mylabel=Vessel::transformName( name ); + plumed_massert( keywords.outputComponentExists(mylabel,false), "a description of the value calculated by vessel " + name + " has not been added to the manual"); + } addVessel(vv); } -void ActionWithVessel::addVessel( Vessel* vv ){ +void ActionWithVessel::addVessel( Vessel* vv ) { ShortcutVessel* sv=dynamic_cast<ShortcutVessel*>(vv); - if(!sv){ vv->checkRead(); functions.push_back(vv); } + if(!sv) { vv->checkRead(); functions.push_back(vv); } else { delete sv; return; } StoreDataVessel* mm=dynamic_cast<StoreDataVessel*>( vv ); if( mydata && mm ) error("cannot have more than one StoreDataVessel in one action"); else if( mm ) mydata=mm; - else dertime_can_be_off=false; + else dertime_can_be_off=false; } -BridgeVessel* ActionWithVessel::addBridgingVessel( ActionWithVessel* tome ){ - VesselOptions da("","",0,"",this); +BridgeVessel* ActionWithVessel::addBridgingVessel( ActionWithVessel* tome ) { + VesselOptions da("","",0,"",this); BridgeVessel* bv=new BridgeVessel(da); bv->setOutputAction( tome ); tome->actionIsBridged=true; dertime_can_be_off=false; functions.push_back( dynamic_cast<Vessel*>(bv) ); resizeFunctions(); - return bv; + return bv; } -StoreDataVessel* ActionWithVessel::buildDataStashes( ActionWithVessel* actionThatUses ){ - if(mydata){ - if( actionThatUses ) mydata->addActionThatUses( actionThatUses ); - return mydata; - } - +StoreDataVessel* ActionWithVessel::buildDataStashes( ActionWithVessel* actionThatUses ) { + if(mydata) { + if( actionThatUses ) mydata->addActionThatUses( actionThatUses ); + return mydata; + } + VesselOptions da("","",0,"",this); StoreDataVessel* mm=new StoreDataVessel(da); if( actionThatUses ) mm->addActionThatUses( actionThatUses ); @@ -149,86 +149,86 @@ StoreDataVessel* ActionWithVessel::buildDataStashes( ActionWithVessel* actionTha return mydata; } -void ActionWithVessel::addTaskToList( const unsigned& taskCode ){ - fullTaskList.push_back( taskCode ); taskFlags.push_back(0); +void ActionWithVessel::addTaskToList( const unsigned& taskCode ) { + fullTaskList.push_back( taskCode ); taskFlags.push_back(0); plumed_assert( fullTaskList.size()==taskFlags.size() ); } -void ActionWithVessel::readVesselKeywords(){ +void ActionWithVessel::readVesselKeywords() { // Set maxderivatives if it is too big if( maxderivatives>getNumberOfDerivatives() ) maxderivatives=getNumberOfDerivatives(); // Loop over all keywords find the vessels and create appropriate functions - for(unsigned i=0;i<keywords.size();++i){ - std::string thiskey,input; thiskey=keywords.getKeyword(i); - // Check if this is a key for a vessel - if( vesselRegister().check(thiskey) ){ - plumed_assert( keywords.style(thiskey,"vessel") ); - bool dothis=false; parseFlag(thiskey,dothis); - if(dothis) addVessel( thiskey, input ); - - parse(thiskey,input); - if(input.size()!=0){ - addVessel( thiskey, input ); - } else { - for(unsigned i=1;;++i){ - if( !parseNumbered(thiskey,i,input) ) break; - std::string ss; Tools::convert(i,ss); - addVessel( thiskey, input, i ); - input.clear(); - } - } + for(unsigned i=0; i<keywords.size(); ++i) { + std::string thiskey,input; thiskey=keywords.getKeyword(i); + // Check if this is a key for a vessel + if( vesselRegister().check(thiskey) ) { + plumed_assert( keywords.style(thiskey,"vessel") ); + bool dothis=false; parseFlag(thiskey,dothis); + if(dothis) addVessel( thiskey, input ); + + parse(thiskey,input); + if(input.size()!=0) { + addVessel( thiskey, input ); + } else { + for(unsigned i=1;; ++i) { + if( !parseNumbered(thiskey,i,input) ) break; + std::string ss; Tools::convert(i,ss); + addVessel( thiskey, input, i ); + input.clear(); + } } + } } // Make sure all vessels have had been resized at start if( functions.size()>0 ) resizeFunctions(); } -void ActionWithVessel::resizeFunctions(){ - for(unsigned i=0;i<functions.size();++i) functions[i]->resize(); +void ActionWithVessel::resizeFunctions() { + for(unsigned i=0; i<functions.size(); ++i) functions[i]->resize(); } -void ActionWithVessel::needsDerivatives(){ +void ActionWithVessel::needsDerivatives() { // Turn on the derivatives and resize - noderiv=false; resizeFunctions(); + noderiv=false; resizeFunctions(); // Setting contributors unlocked here ensures that link cells are ignored contributorsAreUnlocked=true; contributorsAreUnlocked=false; // And turn on the derivatives in all actions on which we are dependent - for(unsigned i=0;i<getDependencies().size();++i){ - ActionWithVessel* vv=dynamic_cast<ActionWithVessel*>( getDependencies()[i] ); - if(vv) vv->needsDerivatives(); + for(unsigned i=0; i<getDependencies().size(); ++i) { + ActionWithVessel* vv=dynamic_cast<ActionWithVessel*>( getDependencies()[i] ); + if(vv) vv->needsDerivatives(); } } -void ActionWithVessel::lockContributors(){ +void ActionWithVessel::lockContributors() { nactive_tasks = 0; - for(unsigned i=0;i<fullTaskList.size();++i){ - if( taskFlags[i]>0 ) nactive_tasks++; + for(unsigned i=0; i<fullTaskList.size(); ++i) { + if( taskFlags[i]>0 ) nactive_tasks++; } unsigned n=0; partialTaskList.resize( nactive_tasks ); - indexOfTaskInFullList.resize( nactive_tasks ); - for(unsigned i=0;i<fullTaskList.size();++i){ - // Deactivate sets inactive tasks to number not equal to zero - if( taskFlags[i]>0 ){ - partialTaskList[n] = fullTaskList[i]; - indexOfTaskInFullList[n]=i; - n++; - } + indexOfTaskInFullList.resize( nactive_tasks ); + for(unsigned i=0; i<fullTaskList.size(); ++i) { + // Deactivate sets inactive tasks to number not equal to zero + if( taskFlags[i]>0 ) { + partialTaskList[n] = fullTaskList[i]; + indexOfTaskInFullList[n]=i; + n++; + } } plumed_dbg_assert( n==nactive_tasks ); - for(unsigned i=0;i<functions.size();++i){ - BridgeVessel* bb = dynamic_cast<BridgeVessel*>( functions[i] ); - if( bb ) bb->copyTaskFlags(); + for(unsigned i=0; i<functions.size(); ++i) { + BridgeVessel* bb = dynamic_cast<BridgeVessel*>( functions[i] ); + if( bb ) bb->copyTaskFlags(); } // Resize mydata to accomodate all active tasks if( mydata ) mydata->resize(); contributorsAreUnlocked=false; } -void ActionWithVessel::deactivateAllTasks(){ +void ActionWithVessel::deactivateAllTasks() { contributorsAreUnlocked=true; nactive_tasks = 0; taskFlags.assign(taskFlags.size(),0); } @@ -237,26 +237,26 @@ bool ActionWithVessel::taskIsCurrentlyActive( const unsigned& index ) const { plumed_dbg_assert( index<taskFlags.size() ); return (taskFlags[index]>0); } -void ActionWithVessel::doJobsRequiredBeforeTaskList(){ +void ActionWithVessel::doJobsRequiredBeforeTaskList() { // Do any preparatory stuff for functions - for(unsigned j=0;j<functions.size();++j) functions[j]->prepare(); + for(unsigned j=0; j<functions.size(); ++j) functions[j]->prepare(); } -unsigned ActionWithVessel::getSizeOfBuffer( unsigned& bufsize ){ - for(unsigned i=0;i<functions.size();++i) functions[i]->setBufferStart( bufsize ); +unsigned ActionWithVessel::getSizeOfBuffer( unsigned& bufsize ) { + for(unsigned i=0; i<functions.size(); ++i) functions[i]->setBufferStart( bufsize ); if( buffer.size()!=bufsize ) buffer.resize( bufsize ); - if( mydata ){ - unsigned dsize=mydata->getSizeOfDerivativeList(); - if( der_list.size()!=dsize ) der_list.resize( dsize ); + if( mydata ) { + unsigned dsize=mydata->getSizeOfDerivativeList(); + if( der_list.size()!=dsize ) der_list.resize( dsize ); } return bufsize; } -void ActionWithVessel::runAllTasks(){ +void ActionWithVessel::runAllTasks() { plumed_massert( !contributorsAreUnlocked && functions.size()>0, "you must have a call to readVesselKeywords somewhere" ); unsigned stride=comm.Get_size(); unsigned rank=comm.Get_rank(); - if(serial){ stride=1; rank=0; } + if(serial) { stride=1; rank=0; } // Make sure jobs are done if(timers) stopwatch.start("1 Prepare Tasks"); @@ -269,55 +269,55 @@ void ActionWithVessel::runAllTasks(){ if( nt==0 || !threadSafe() ) nt=1; // Get size for buffer - unsigned bsize=0, bufsize=getSizeOfBuffer( bsize ); + unsigned bsize=0, bufsize=getSizeOfBuffer( bsize ); // Clear buffer buffer.assign( buffer.size(), 0.0 ); // Switch off calculation of derivatives in main loop if( dertime_can_be_off ) dertime=false; // std::vector<unsigned> der_list; - // if( mydata ) der_list.resize( mydata->getSizeOfDerivativeList(), 0 ); + // if( mydata ) der_list.resize( mydata->getSizeOfDerivativeList(), 0 ); // Build storage stuff for loop // std::vector<double> buffer( bufsize, 0.0 ); if(timers) stopwatch.start("2 Loop over tasks"); -#pragma omp parallel num_threads(nt) -{ - std::vector<double> omp_buffer; - if( nt>1 ) omp_buffer.resize( bufsize, 0.0 ); - MultiValue myvals( getNumberOfQuantities(), getNumberOfDerivatives() ); - MultiValue bvals( getNumberOfQuantities(), getNumberOfDerivatives() ); - myvals.clearAll(); bvals.clearAll(); - -#pragma omp for nowait - for(unsigned i=rank;i<nactive_tasks;i+=stride){ + #pragma omp parallel num_threads(nt) + { + std::vector<double> omp_buffer; + if( nt>1 ) omp_buffer.resize( bufsize, 0.0 ); + MultiValue myvals( getNumberOfQuantities(), getNumberOfDerivatives() ); + MultiValue bvals( getNumberOfQuantities(), getNumberOfDerivatives() ); + myvals.clearAll(); bvals.clearAll(); + + #pragma omp for nowait + for(unsigned i=rank; i<nactive_tasks; i+=stride) { // Calculate the stuff in the loop for this action performTask( indexOfTaskInFullList[i], partialTaskList[i], myvals ); // Check for conditions that allow us to just to skip the calculation - // the condition is that the weight of the contribution is low + // the condition is that the weight of the contribution is low // N.B. Here weights are assumed to be between zero and one - if( myvals.get(0)<tolerance ){ - // Clear the derivatives - myvals.clearAll(); - continue; + if( myvals.get(0)<tolerance ) { + // Clear the derivatives + myvals.clearAll(); + continue; } // Now calculate all the functions // If the contribution of this quantity is very small at neighbour list time ignore it // untill next neighbour list time - if( nt>1 ){ - calculateAllVessels( indexOfTaskInFullList[i], myvals, bvals, omp_buffer, der_list ); + if( nt>1 ) { + calculateAllVessels( indexOfTaskInFullList[i], myvals, bvals, omp_buffer, der_list ); } else { - calculateAllVessels( indexOfTaskInFullList[i], myvals, bvals, buffer, der_list ); + calculateAllVessels( indexOfTaskInFullList[i], myvals, bvals, buffer, der_list ); } // Clear the value myvals.clearAll(); + } + #pragma omp critical + if(nt>1) for(unsigned i=0; i<bufsize; ++i) buffer[i]+=omp_buffer[i]; } -#pragma omp critical - if(nt>1) for(unsigned i=0;i<bufsize;++i) buffer[i]+=omp_buffer[i]; -} if(timers) stopwatch.stop("2 Loop over tasks"); // Turn back on derivative calculation dertime=true; @@ -326,8 +326,8 @@ void ActionWithVessel::runAllTasks(){ // MPI Gather everything if( !serial && buffer.size()>0 ) comm.Sum( buffer ); // MPI Gather index stores - if( mydata && !lowmem && !noderiv ){ - comm.Sum( der_list ); mydata->setActiveValsAndDerivatives( der_list ); + if( mydata && !lowmem && !noderiv ) { + comm.Sum( der_list ); mydata->setActiveValsAndDerivatives( der_list ); } // Update the elements that are makign contributions to the sum here // this causes problems if we do it in prepare @@ -342,22 +342,22 @@ void ActionWithVessel::transformBridgedDerivatives( const unsigned& current, Mul plumed_error(); } -void ActionWithVessel::calculateAllVessels( const unsigned& taskCode, MultiValue& myvals, MultiValue& bvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ){ - for(unsigned j=0;j<functions.size();++j){ - // Calculate returns a bool that tells us if this particular - // quantity is contributing more than the tolerance - functions[j]->calculate( taskCode, functions[j]->transformDerivatives(taskCode, myvals, bvals), buffer, der_list ); - if( !actionIsBridged ) bvals.clearAll(); +void ActionWithVessel::calculateAllVessels( const unsigned& taskCode, MultiValue& myvals, MultiValue& bvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) { + for(unsigned j=0; j<functions.size(); ++j) { + // Calculate returns a bool that tells us if this particular + // quantity is contributing more than the tolerance + functions[j]->calculate( taskCode, functions[j]->transformDerivatives(taskCode, myvals, bvals), buffer, der_list ); + if( !actionIsBridged ) bvals.clearAll(); } return; } -void ActionWithVessel::finishComputations( const std::vector<double>& buffer ){ +void ActionWithVessel::finishComputations( const std::vector<double>& buffer ) { // Set the final value of the function - for(unsigned j=0;j<functions.size();++j) functions[j]->finish( buffer ); + for(unsigned j=0; j<functions.size(); ++j) functions[j]->finish( buffer ); } -bool ActionWithVessel::getForcesFromVessels( std::vector<double>& forcesToApply ){ +bool ActionWithVessel::getForcesFromVessels( std::vector<double>& forcesToApply ) { #ifndef NDEBUG if( forcesToApply.size()>0 ) plumed_dbg_assert( forcesToApply.size()==getNumberOfDerivatives() ); #endif @@ -365,26 +365,26 @@ bool ActionWithVessel::getForcesFromVessels( std::vector<double>& forcesToApply forcesToApply.assign( forcesToApply.size(),0.0 ); bool wasforced=false; - for(unsigned i=0;i<getNumberOfVessels();++i){ - if( (functions[i]->applyForce( tmpforces )) ){ - wasforced=true; - for(unsigned j=0;j<forcesToApply.size();++j) forcesToApply[j]+=tmpforces[j]; + for(unsigned i=0; i<getNumberOfVessels(); ++i) { + if( (functions[i]->applyForce( tmpforces )) ) { + wasforced=true; + for(unsigned j=0; j<forcesToApply.size(); ++j) forcesToApply[j]+=tmpforces[j]; } } return wasforced; } -void ActionWithVessel::retrieveDomain( std::string& min, std::string& max ){ +void ActionWithVessel::retrieveDomain( std::string& min, std::string& max ) { plumed_merror("If your function is periodic you need to add a retrieveDomain function so that ActionWithVessel can retrieve the domain"); } -Vessel* ActionWithVessel::getVesselWithName( const std::string& mynam ){ +Vessel* ActionWithVessel::getVesselWithName( const std::string& mynam ) { int target=-1; - for(unsigned i=0;i<functions.size();++i){ - if( functions[i]->getName().find(mynam)!=std::string::npos ){ - if( target<0 ) target=i; - else error("found more than one " + mynam + " object in action"); - } + for(unsigned i=0; i<functions.size(); ++i) { + if( functions[i]->getName().find(mynam)!=std::string::npos ) { + if( target<0 ) target=i; + else error("found more than one " + mynam + " object in action"); + } } return functions[target]; } diff --git a/src/vesselbase/ActionWithVessel.h b/src/vesselbase/ActionWithVessel.h index a20954804..813403764 100644 --- a/src/vesselbase/ActionWithVessel.h +++ b/src/vesselbase/ActionWithVessel.h @@ -29,11 +29,11 @@ #include "tools/MultiValue.h" #include <vector> -namespace PLMD{ +namespace PLMD { class Value; class Stopwatch; -namespace vesselbase{ +namespace vesselbase { class Vessel; class BridgeVessel; @@ -46,13 +46,13 @@ times. This is used in PLMD::MultiColvar. */ class ActionWithVessel : public virtual Action { -friend class Vessel; -friend class ShortcutVessel; -friend class FunctionVessel; -friend class StoreDataVessel; -friend class BridgeVessel; -friend class ActionWithInputVessel; -friend class OrderingVessel; + friend class Vessel; + friend class ShortcutVessel; + friend class FunctionVessel; + friend class StoreDataVessel; + friend class BridgeVessel; + friend class ActionWithInputVessel; + friend class OrderingVessel; private: /// Do all calculations in serial bool serial; @@ -64,7 +64,7 @@ private: bool actionIsBridged; /// The maximum number of derivatives we can use before we need to invoke lowmem unsigned maxderivatives; -/// The tolerance on the accumulators +/// The tolerance on the accumulators double tolerance; /// Tolerance for quantities being put in neighbor lists double nl_tolerance; @@ -120,7 +120,7 @@ protected: void runAllTasks(); /// Resize all the functions when the number of derivatives change void resizeFunctions(); -/// This loops over all the vessels calculating them and also +/// This loops over all the vessels calculating them and also /// sets all the element derivatives equal to zero void calculateAllVessels( const unsigned& taskCode, MultiValue& myvals, MultiValue& bvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ); /// Retrieve the forces from all the vessels (used in apply) @@ -156,14 +156,14 @@ public: virtual bool isPeriodic()=0; /// What are the domains of the base quantities virtual void retrieveDomain( std::string& min, std::string& max); -/// Get the number of derivatives for final calculated quantity +/// Get the number of derivatives for final calculated quantity virtual unsigned getNumberOfDerivatives()=0; /// Get the number of quantities that are calculated during each task virtual unsigned getNumberOfQuantities() const ; /// Get the number of vessels unsigned getNumberOfVessels() const; /// Get a pointer to the ith vessel - Vessel* getPntrToVessel( const unsigned& i ); + Vessel* getPntrToVessel( const unsigned& i ); /// Do any jobs that are required before the task list is undertaken virtual void doJobsRequiredBeforeTaskList(); /// Get the full size of the taskList dynamic list @@ -175,13 +175,13 @@ public: /// Get the ith of the currently active tasks unsigned getActiveTask( const unsigned& ii ) const ; /// Calculate one of the functions in the distribution - virtual void performTask( const unsigned& , const unsigned& , MultiValue& ) const=0; + virtual void performTask( const unsigned&, const unsigned&, MultiValue& ) const=0; /// Do the task if we have a bridge virtual void transformBridgedDerivatives( const unsigned& current, MultiValue& invals, MultiValue& outvals ) const; /// Ensure that data required in other vessels is stored StoreDataVessel* buildDataStashes( ActionWithVessel* actionThatUses ); /// Apply forces from bridge vessel - this is rarely used - currently only in ActionVolume - virtual void applyBridgeForces( const std::vector<double>& bb ){ plumed_error(); } + virtual void applyBridgeForces( const std::vector<double>& bb ) { plumed_error(); } /// These are overwritten in MultiColvarFunction // virtual void activateIndexes( const unsigned&, const unsigned&, const std::vector<unsigned>& ){} /// Return a particular named vessel @@ -216,7 +216,7 @@ unsigned ActionWithVessel::getNumberOfQuantities() const { } inline -Vessel* ActionWithVessel::getPntrToVessel( const unsigned& i ){ +Vessel* ActionWithVessel::getPntrToVessel( const unsigned& i ) { plumed_dbg_assert( i<functions.size() ); return functions[i]; } @@ -260,7 +260,7 @@ bool ActionWithVessel::usingLowMem() const { } inline -void ActionWithVessel::setLowMemOption(const bool& l){ +void ActionWithVessel::setLowMemOption(const bool& l) { lowmem=l; } @@ -278,12 +278,12 @@ inline unsigned ActionWithVessel::getPositionInCurrentTaskList( const unsigned& myind ) const { if( nactive_tasks==fullTaskList.size() ) return myind; - for(unsigned i=0;i<nactive_tasks;++i){ - if( myind==indexOfTaskInFullList[i] ) return i; + for(unsigned i=0; i<nactive_tasks; ++i) { + if( myind==indexOfTaskInFullList[i] ) return i; } plumed_merror("requested task is not active"); } -} +} } #endif diff --git a/src/vesselbase/AltMin.cpp b/src/vesselbase/AltMin.cpp index 7ade92fe0..7dfa034d6 100644 --- a/src/vesselbase/AltMin.cpp +++ b/src/vesselbase/AltMin.cpp @@ -39,28 +39,28 @@ public: PLUMED_REGISTER_VESSEL(AltMin,"ALT_MIN") -void AltMin::registerKeywords( Keywords& keys ){ +void AltMin::registerKeywords( Keywords& keys ) { FunctionVessel::registerKeywords(keys); keys.add("compulsory","BETA","the value of beta for the equation in the manual"); } -void AltMin::reserveKeyword( Keywords& keys ){ +void AltMin::reserveKeyword( Keywords& keys ) { keys.reserve("vessel","ALT_MIN","calculate the minimum value. " - "To make this quantity continuous the minimum is calculated using " - "\\f$ \\textrm{min} = -\\frac{1}{\\beta} \\log \\sum_i \\exp\\left( -\\beta s_i \\right) \\f$ " - "The value of \\f$\\beta\\f$ in this function is specified using (BETA=\\f$\\beta\\f$)."); + "To make this quantity continuous the minimum is calculated using " + "\\f$ \\textrm{min} = -\\frac{1}{\\beta} \\log \\sum_i \\exp\\left( -\\beta s_i \\right) \\f$ " + "The value of \\f$\\beta\\f$ in this function is specified using (BETA=\\f$\\beta\\f$)."); keys.addOutputComponent("altmin","ALT_MIN","the minimum value. This is calculated using the formula described in the description of the " - "keyword so as to make it continuous."); + "keyword so as to make it continuous."); } AltMin::AltMin( const vesselbase::VesselOptions& da ): -FunctionVessel(da) + FunctionVessel(da) { if( getAction()->isPeriodic() ) error("MIN is not a meaningful option for periodic variables"); parse("BETA",beta); usetol=true; } -std::string AltMin::value_descriptor(){ +std::string AltMin::value_descriptor() { std::string str_beta; Tools::convert( beta, str_beta ); return "the minimum value. Beta is equal to " + str_beta; } @@ -69,9 +69,9 @@ double AltMin::calcTransform( const double& val, double& dv ) const { double f = exp( -beta*val ); dv = -beta*f; return f; } -double AltMin::finalTransform( const double& val, double& dv ){ - dv = - 1.0 /(beta*val); return -std::log( val ) / beta; -} +double AltMin::finalTransform( const double& val, double& dv ) { + dv = - 1.0 /(beta*val); return -std::log( val ) / beta; +} } } diff --git a/src/vesselbase/AveragingVessel.cpp b/src/vesselbase/AveragingVessel.cpp index 7d8933bd6..a3bbb4fd7 100644 --- a/src/vesselbase/AveragingVessel.cpp +++ b/src/vesselbase/AveragingVessel.cpp @@ -25,35 +25,35 @@ namespace PLMD { namespace vesselbase { -void AveragingVessel::registerKeywords( Keywords& keys ){ +void AveragingVessel::registerKeywords( Keywords& keys ) { Vessel::registerKeywords( keys ); } AveragingVessel::AveragingVessel( const vesselbase::VesselOptions& vo ): -Vessel(vo), -wascleared(true) + Vessel(vo), + wascleared(true) { ActionWithAveraging* myav = dynamic_cast<ActionWithAveraging*>( getAction() ); plumed_assert( myav ); unormalised = myav->unormalised; } -void AveragingVessel::finish( const std::vector<double>& buffer ){ - wascleared=false; for(unsigned i=1;i<data.size();++i) data[i]+=buffer[bufstart + i - 1]; +void AveragingVessel::finish( const std::vector<double>& buffer ) { + wascleared=false; for(unsigned i=1; i<data.size(); ++i) data[i]+=buffer[bufstart + i - 1]; } bool AveragingVessel::wasreset() const { return wascleared; } -void AveragingVessel::clear(){ - plumed_assert( wascleared ); data.assign( data.size(), 0.0 ); +void AveragingVessel::clear() { + plumed_assert( wascleared ); data.assign( data.size(), 0.0 ); } -void AveragingVessel::reset(){ - wascleared=true; +void AveragingVessel::reset() { + wascleared=true; } -void AveragingVessel::setDataSize( const unsigned& size ){ +void AveragingVessel::setDataSize( const unsigned& size ) { if( data.size()!=(1+size) ) data.resize( 1+size, 0 ); } diff --git a/src/vesselbase/AveragingVessel.h b/src/vesselbase/AveragingVessel.h index 0d5ad0cfb..ad9bb4cb4 100644 --- a/src/vesselbase/AveragingVessel.h +++ b/src/vesselbase/AveragingVessel.h @@ -30,62 +30,62 @@ namespace vesselbase { class AveragingVessel : public Vessel { private: /// The grid was recently cleared and bounds can be set - bool wascleared; + bool wascleared; /// Are we outputting unormalised data - bool unormalised; + bool unormalised; /// The data that is being averaged - std::vector<double> data; + std::vector<double> data; protected: /// Set the size of the data vector - void setDataSize( const unsigned& size ); + void setDataSize( const unsigned& size ); /// Set an element of the data array - void setDataElement( const unsigned& myelem, const double& value ); + void setDataElement( const unsigned& myelem, const double& value ); /// Add some value to an element of the data array - void addDataElement( const unsigned& myelem, const double& value ); + void addDataElement( const unsigned& myelem, const double& value ); /// Get the value of one of the data element - double getDataElement( const unsigned& myelem ) const ; + double getDataElement( const unsigned& myelem ) const ; /// Are we averaging the data - bool noAverage() const { return unormalised; } + bool noAverage() const { return unormalised; } public: /// keywords - static void registerKeywords( Keywords& keys ); + static void registerKeywords( Keywords& keys ); /// Constructor - explicit AveragingVessel( const vesselbase::VesselOptions& ); + explicit AveragingVessel( const vesselbase::VesselOptions& ); /// Copy data from an accumulated buffer into the grid - virtual void finish( const std::vector<double>& ); + virtual void finish( const std::vector<double>& ); /// Was the grid cleared on the last step - bool wasreset() const ; + bool wasreset() const ; /// Clear all the data stored on the grid - virtual void clear(); + virtual void clear(); /// Reset the grid so that it is cleared at start of next time it is calculated - virtual void reset(); + virtual void reset(); /// Functions for dealing with normalisation constant - void setNorm( const double& snorm ); - double getNorm() const ; - virtual bool applyForce( std::vector<double>& forces ){ return false; } + void setNorm( const double& snorm ); + double getNorm() const ; + virtual bool applyForce( std::vector<double>& forces ) { return false; } }; inline -void AveragingVessel::setDataElement( const unsigned& myelem, const double& value ){ - plumed_dbg_assert( myelem<1+data.size() ); - wascleared=false; data[1+myelem]=value; +void AveragingVessel::setDataElement( const unsigned& myelem, const double& value ) { + plumed_dbg_assert( myelem<1+data.size() ); + wascleared=false; data[1+myelem]=value; } inline -void AveragingVessel::addDataElement( const unsigned& myelem, const double& value ){ - plumed_dbg_assert( myelem<1+data.size() ); - wascleared=false; data[1+myelem]+=value; +void AveragingVessel::addDataElement( const unsigned& myelem, const double& value ) { + plumed_dbg_assert( myelem<1+data.size() ); + wascleared=false; data[1+myelem]+=value; } inline double AveragingVessel::getDataElement( const unsigned& myelem ) const { - plumed_dbg_assert( myelem<data.size()-1 ); - if( unormalised ) return data[1+myelem]; - return data[1+myelem] / data[0]; + plumed_dbg_assert( myelem<data.size()-1 ); + if( unormalised ) return data[1+myelem]; + return data[1+myelem] / data[0]; } inline -void AveragingVessel::setNorm( const double& snorm ){ +void AveragingVessel::setNorm( const double& snorm ) { plumed_dbg_assert( data.size()>0 ); data[0]=snorm; } diff --git a/src/vesselbase/Between.cpp b/src/vesselbase/Between.cpp index 3a00b2fa7..ac02823d0 100644 --- a/src/vesselbase/Between.cpp +++ b/src/vesselbase/Between.cpp @@ -28,52 +28,52 @@ namespace vesselbase { PLUMED_REGISTER_VESSEL(Between,"BETWEEN") -void Between::registerKeywords( Keywords& keys ){ +void Between::registerKeywords( Keywords& keys ) { FunctionVessel::registerKeywords( keys ); HistogramBead::registerKeywords( keys ); keys.addFlag("NORM",false,"calculate the fraction of values rather than the number"); } -void Between::reserveKeyword( Keywords& keys ){ +void Between::reserveKeyword( Keywords& keys ) { keys.reserve("vessel","BETWEEN","calculate the number of values that are within a certain range. " - "These quantities are calculated using kernel density estimation as described on " - "\\ref histogrambead."); + "These quantities are calculated using kernel density estimation as described on " + "\\ref histogrambead."); keys.addOutputComponent("between","BETWEEN","the number/fraction of values within a certain range. This is calculated using one of the " - "formula described in the description of the keyword so as to make it continuous. " - "You can calculate this quantity multiple times using different parameters."); + "formula described in the description of the keyword so as to make it continuous. " + "You can calculate this quantity multiple times using different parameters."); } Between::Between( const VesselOptions& da ) : -FunctionVessel(da) -{ + FunctionVessel(da) +{ usetol=true; bool isPeriodic=getAction()->isPeriodic(); double min, max; std::string str_min, str_max; - if( isPeriodic ){ - getAction()->retrieveDomain( str_min, str_max ); - Tools::convert(str_min,min); Tools::convert(str_max,max); + if( isPeriodic ) { + getAction()->retrieveDomain( str_min, str_max ); + Tools::convert(str_min,min); Tools::convert(str_max,max); } - parseFlag("NORM",norm); std::string errormsg; + parseFlag("NORM",norm); std::string errormsg; hist.set( getAllInput(),errormsg ); if( !isPeriodic ) hist.isNotPeriodic(); - else hist.isPeriodic( min, max ); + else hist.isPeriodic( min, max ); if( errormsg.size()!=0 ) error( errormsg ); } -std::string Between::value_descriptor(){ +std::string Between::value_descriptor() { if(norm) return "the fraction of values " + hist.description(); return "the number of values " + hist.description(); } double Between::calcTransform( const double& val, double& dv ) const { - double f = hist.calculate(val, dv); return f; + double f = hist.calculate(val, dv); return f; } -double Between::getCutoff(){ +double Between::getCutoff() { return std::numeric_limits<double>::max(); -} +} } } diff --git a/src/vesselbase/BridgeVessel.cpp b/src/vesselbase/BridgeVessel.cpp index 18ba59adb..043f68440 100644 --- a/src/vesselbase/BridgeVessel.cpp +++ b/src/vesselbase/BridgeVessel.cpp @@ -28,31 +28,31 @@ namespace PLMD { namespace vesselbase { BridgeVessel::BridgeVessel( const VesselOptions& da ): -Vessel(da), -inum(0), + Vessel(da), + inum(0), // in_normal_calculate(false) -myOutputAction(NULL), -myOutputValues(NULL), -my_tmp_val(0,0) + myOutputAction(NULL), + myOutputValues(NULL), + my_tmp_val(0,0) { } -void BridgeVessel::resize(){ - if( myOutputAction->checkNumericalDerivatives() ){ - mynumerical_values.resize( getAction()->getNumberOfDerivatives()*myOutputValues->getNumberOfComponents() ); - inum=0; +void BridgeVessel::resize() { + if( myOutputAction->checkNumericalDerivatives() ) { + mynumerical_values.resize( getAction()->getNumberOfDerivatives()*myOutputValues->getNumberOfComponents() ); + inum=0; } // This bit ensures that we can store data in a bridge function if needs be // Notice we need to resize der_list in the underlying action as this is called // from a bridge - if( myOutputAction->mydata ){ - unsigned dsize=(myOutputAction->mydata)->getSizeOfDerivativeList(); - if( getAction()->der_list.size()!=dsize ) getAction()->der_list.resize( dsize ); + if( myOutputAction->mydata ) { + unsigned dsize=(myOutputAction->mydata)->getSizeOfDerivativeList(); + if( getAction()->der_list.size()!=dsize ) getAction()->der_list.resize( dsize ); } unsigned tmp=0; resizeBuffer( myOutputAction->getSizeOfBuffer( tmp ) ); } -void BridgeVessel::setOutputAction( ActionWithVessel* myact ){ +void BridgeVessel::setOutputAction( ActionWithVessel* myact ) { ActionWithValue* checkme=dynamic_cast<ActionWithValue*>( getAction() ); plumed_massert( checkme, "vessel in bridge must inherit from ActionWithValue"); @@ -61,22 +61,22 @@ void BridgeVessel::setOutputAction( ActionWithVessel* myact ){ plumed_massert( myOutputValues, "bridging vessel must inherit from ActionWithValue"); } -std::string BridgeVessel::description(){ +std::string BridgeVessel::description() { plumed_merror("I shouldn't end up here"); } -void BridgeVessel::prepare(){ +void BridgeVessel::prepare() { myOutputAction->doJobsRequiredBeforeTaskList(); } -void BridgeVessel::setBufferStart( unsigned& start ){ +void BridgeVessel::setBufferStart( unsigned& start ) { unsigned tmp=myOutputAction->getSizeOfBuffer( start ); } -MultiValue& BridgeVessel::transformDerivatives( const unsigned& current, MultiValue& invals, MultiValue& outvals ){ +MultiValue& BridgeVessel::transformDerivatives( const unsigned& current, MultiValue& invals, MultiValue& outvals ) { if( outvals.getNumberOfValues()!=myOutputAction->getNumberOfQuantities() || - outvals.getNumberOfDerivatives()!=myOutputAction->getNumberOfDerivatives() ){ - outvals.resize( myOutputAction->getNumberOfQuantities(), myOutputAction->getNumberOfDerivatives() ); + outvals.getNumberOfDerivatives()!=myOutputAction->getNumberOfDerivatives() ) { + outvals.resize( myOutputAction->getNumberOfQuantities(), myOutputAction->getNumberOfDerivatives() ); } myOutputAction->transformBridgedDerivatives( current, invals, outvals ); return outvals; @@ -85,64 +85,64 @@ MultiValue& BridgeVessel::transformDerivatives( const unsigned& current, MultiVa void BridgeVessel::calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const { // in_normal_calculate=true; if( myvals.get(0)<myOutputAction->getTolerance() ) return; - myOutputAction->calculateAllVessels( current, myvals, myvals, buffer, der_list ); - return; + myOutputAction->calculateAllVessels( current, myvals, myvals, buffer, der_list ); + return; } -void BridgeVessel::finish( const std::vector<double>& buffer ){ +void BridgeVessel::finish( const std::vector<double>& buffer ) { myOutputAction->finishComputations( buffer ); - if( myOutputAction->checkNumericalDerivatives() ){ - if ( inum<mynumerical_values.size() ){ - for(int i=0;i<myOutputValues->getNumberOfComponents();++i){ - mynumerical_values[inum]=myOutputValues->getOutputQuantity(i); - inum++; - } - plumed_dbg_assert( inum<=mynumerical_values.size() ); - } else { - plumed_assert( inum==mynumerical_values.size() ); - } - } + if( myOutputAction->checkNumericalDerivatives() ) { + if ( inum<mynumerical_values.size() ) { + for(int i=0; i<myOutputValues->getNumberOfComponents(); ++i) { + mynumerical_values[inum]=myOutputValues->getOutputQuantity(i); + inum++; + } + plumed_dbg_assert( inum<=mynumerical_values.size() ); + } else { + plumed_assert( inum==mynumerical_values.size() ); + } + } } -void BridgeVessel::completeNumericalDerivatives(){ +void BridgeVessel::completeNumericalDerivatives() { unsigned nextra = myOutputAction->getNumberOfDerivatives() - getAction()->getNumberOfDerivatives(); Matrix<double> tmpder( myOutputValues->getNumberOfComponents(), nextra ); ActionWithVessel* vval=dynamic_cast<ActionWithVessel*>( myOutputAction ); - for(unsigned i=0;i<nextra;++i){ - vval->bridgeVariable=i; getAction()->calculate(); - for(int j=0;j<myOutputValues->getNumberOfComponents();++j) tmpder(j,i) = myOutputValues->getOutputQuantity(j); + for(unsigned i=0; i<nextra; ++i) { + vval->bridgeVariable=i; getAction()->calculate(); + for(int j=0; j<myOutputValues->getNumberOfComponents(); ++j) tmpder(j,i) = myOutputValues->getOutputQuantity(j); } - vval->bridgeVariable=nextra; getAction()->calculate(); + vval->bridgeVariable=nextra; getAction()->calculate(); plumed_assert( inum==mynumerical_values.size() ); inum=0; // Reset inum now that we have finished calling calculate std::vector<double> base( myOutputValues->getNumberOfComponents() ); - for(int j=0;j<myOutputValues->getNumberOfComponents();++j) base[j] = myOutputValues->getOutputQuantity(j); + for(int j=0; j<myOutputValues->getNumberOfComponents(); ++j) base[j] = myOutputValues->getOutputQuantity(j); const double delta=sqrt(epsilon); ActionAtomistic* aa=dynamic_cast<ActionAtomistic*>( getAction() ); unsigned nvals=myOutputValues->getNumberOfComponents(); - for(unsigned j=0;j<nvals;++j) ( myOutputValues->copyOutput(j) )->clearDerivatives(); - - if( aa ){ - ActionWithArguments* aarg=dynamic_cast<ActionWithArguments*>( getAction() ); - plumed_assert( !aarg ); Tensor box=aa->getBox(); - unsigned natoms=aa->getNumberOfAtoms(); - for(unsigned j=0;j<nvals;++j){ - double ref=( myOutputValues->copyOutput(j) )->get(); - if( ( myOutputValues->copyOutput(j) )->getNumberOfDerivatives()>0 ){ - for(unsigned i=0;i<3*natoms;++i){ - double d=( mynumerical_values[i*nvals+j] - ref)/delta; - ( myOutputValues->copyOutput(j) )->addDerivative(i,d); - } - Tensor virial; - for(int i=0;i<3;i++) for(int k=0;k<3;k++){ - virial(i,k)=( mynumerical_values[ nvals*(3*natoms + 3*i + k) + j ]-ref)/delta; - } - virial=-matmul(box.transpose(),virial); - for(int i=0;i<3;i++) for(int k=0;k<3;k++) ( myOutputValues->copyOutput(j) )->addDerivative(3*natoms+3*k+i,virial(k,i)); + for(unsigned j=0; j<nvals; ++j) ( myOutputValues->copyOutput(j) )->clearDerivatives(); + + if( aa ) { + ActionWithArguments* aarg=dynamic_cast<ActionWithArguments*>( getAction() ); + plumed_assert( !aarg ); Tensor box=aa->getBox(); + unsigned natoms=aa->getNumberOfAtoms(); + for(unsigned j=0; j<nvals; ++j) { + double ref=( myOutputValues->copyOutput(j) )->get(); + if( ( myOutputValues->copyOutput(j) )->getNumberOfDerivatives()>0 ) { + for(unsigned i=0; i<3*natoms; ++i) { + double d=( mynumerical_values[i*nvals+j] - ref)/delta; + ( myOutputValues->copyOutput(j) )->addDerivative(i,d); + } + Tensor virial; + for(int i=0; i<3; i++) for(int k=0; k<3; k++) { + virial(i,k)=( mynumerical_values[ nvals*(3*natoms + 3*i + k) + j ]-ref)/delta; } + virial=-matmul(box.transpose(),virial); + for(int i=0; i<3; i++) for(int k=0; k<3; k++) ( myOutputValues->copyOutput(j) )->addDerivative(3*natoms+3*k+i,virial(k,i)); } + } } else { - plumed_merror("not implemented or tested yet"); + plumed_merror("not implemented or tested yet"); // unsigned nder=myOutputAction->getNumberOfDerivatives(); // for(unsigned j=0;j<nvals;++j){ // double ref=( myOutputValues->copyOutput(j) )->get(); @@ -154,37 +154,37 @@ void BridgeVessel::completeNumericalDerivatives(){ // } } // Add the derivatives wrt to the local quantities we are working with - for(unsigned j=0;j<nvals;++j){ - unsigned k=0; - for(unsigned i=getAction()->getNumberOfDerivatives();i<myOutputAction->getNumberOfDerivatives();++i){ - ( myOutputValues->copyOutput(j) )->addDerivative( i, (tmpder(j,k)-base[j])/sqrt(epsilon) ); k++; - } + for(unsigned j=0; j<nvals; ++j) { + unsigned k=0; + for(unsigned i=getAction()->getNumberOfDerivatives(); i<myOutputAction->getNumberOfDerivatives(); ++i) { + ( myOutputValues->copyOutput(j) )->addDerivative( i, (tmpder(j,k)-base[j])/sqrt(epsilon) ); k++; + } } } -bool BridgeVessel::applyForce( std::vector<double>& outforces ){ +bool BridgeVessel::applyForce( std::vector<double>& outforces ) { bool hasforce=false; outforces.assign(outforces.size(),0.0); unsigned ndertot = myOutputAction->getNumberOfDerivatives(); unsigned nextra = ndertot - getAction()->getNumberOfDerivatives(); std::vector<double> forces( ndertot ), eforces( nextra, 0.0 ); - for(unsigned i=0;i<myOutputAction->getNumberOfVessels();++i){ - if( ( myOutputAction->getPntrToVessel(i) )->applyForce( forces ) ){ - hasforce=true; - for(unsigned j=0;j<outforces.size();++j) outforces[j]+=forces[j]; - for(unsigned j=0;j<nextra;++j) eforces[j]+=forces[ outforces.size()+j ]; - } + for(unsigned i=0; i<myOutputAction->getNumberOfVessels(); ++i) { + if( ( myOutputAction->getPntrToVessel(i) )->applyForce( forces ) ) { + hasforce=true; + for(unsigned j=0; j<outforces.size(); ++j) outforces[j]+=forces[j]; + for(unsigned j=0; j<nextra; ++j) eforces[j]+=forces[ outforces.size()+j ]; + } } if(hasforce) myOutputAction->applyBridgeForces( eforces ); return hasforce; } -void BridgeVessel::copyTaskFlags(){ +void BridgeVessel::copyTaskFlags() { myOutputAction->deactivateAllTasks(); - for(unsigned i=0;i<getAction()->nactive_tasks;++i) myOutputAction->taskFlags[ getAction()->indexOfTaskInFullList[i] ] = 1; + for(unsigned i=0; i<getAction()->nactive_tasks; ++i) myOutputAction->taskFlags[ getAction()->indexOfTaskInFullList[i] ] = 1; myOutputAction->lockContributors(); } -MultiValue& BridgeVessel::getTemporyMultiValue(){ +MultiValue& BridgeVessel::getTemporyMultiValue() { return my_tmp_val; } diff --git a/src/vesselbase/BridgeVessel.h b/src/vesselbase/BridgeVessel.h index 6e0d4f685..2ae248c83 100644 --- a/src/vesselbase/BridgeVessel.h +++ b/src/vesselbase/BridgeVessel.h @@ -35,7 +35,7 @@ namespace vesselbase { /** \ingroup TOOLBOX This class allows you to calculate the vessel in one ActionWithVessel. The user thinks -it is created in a different Action however. At the moment this is used for region +it is created in a different Action however. At the moment this is used for region */ class BridgeVessel : public Vessel { @@ -57,13 +57,13 @@ public: ActionWithVessel* getOutputAction(); /// Setup the action we are outputting to void setOutputAction( ActionWithVessel* myOutputAction ); -/// Apply some force +/// Apply some force bool applyForce( std::vector<double>& forces ); /// Should not be called std::string description(); /// Jobs to do before the task list starts void prepare(); -/// Set the start of the buffer +/// Set the start of the buffer void setBufferStart( unsigned& start ); /// This transforms the derivatives using the output value MultiValue& transformDerivatives( const unsigned& current, MultiValue& invals, MultiValue& outvals ); @@ -76,11 +76,11 @@ public: /// Set the task flags in the bridged class the same as in the original class void copyTaskFlags(); /// Return a tempory multi value - we do this so as to avoid vector resizing - MultiValue& getTemporyMultiValue(); + MultiValue& getTemporyMultiValue(); }; inline -ActionWithVessel* BridgeVessel::getOutputAction(){ +ActionWithVessel* BridgeVessel::getOutputAction() { return myOutputAction; } diff --git a/src/vesselbase/FunctionVessel.cpp b/src/vesselbase/FunctionVessel.cpp index 11dd055a6..13b84e615 100644 --- a/src/vesselbase/FunctionVessel.cpp +++ b/src/vesselbase/FunctionVessel.cpp @@ -22,80 +22,80 @@ #include "FunctionVessel.h" #include "core/ActionWithValue.h" -namespace PLMD{ -namespace vesselbase{ +namespace PLMD { +namespace vesselbase { -void FunctionVessel::registerKeywords( Keywords& keys ){ +void FunctionVessel::registerKeywords( Keywords& keys ) { ValueVessel::registerKeywords( keys ); } FunctionVessel::FunctionVessel( const VesselOptions& da ): -ValueVessel(da), -norm(false), -usetol(false) + ValueVessel(da), + norm(false), + usetol(false) { diffweight=getAction()->weightHasDerivatives; } -void FunctionVessel::resize(){ - if( getAction()->derivativesAreRequired() ){ - unsigned nderivatives=getAction()->getNumberOfDerivatives(); - getFinalValue()->resizeDerivatives( nderivatives ); - resizeBuffer( (1+nderivatives)*2 ); - diffweight=getAction()->weightHasDerivatives; +void FunctionVessel::resize() { + if( getAction()->derivativesAreRequired() ) { + unsigned nderivatives=getAction()->getNumberOfDerivatives(); + getFinalValue()->resizeDerivatives( nderivatives ); + resizeBuffer( (1+nderivatives)*2 ); + diffweight=getAction()->weightHasDerivatives; } else { - resizeBuffer(2); - diffweight=false; // Don't need to worry about differentiable weights if no derivatives + resizeBuffer(2); + diffweight=false; // Don't need to worry about differentiable weights if no derivatives } } void FunctionVessel::calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const { unsigned nderivatives=getFinalValue()->getNumberOfDerivatives(); - double weight=myvals.get(0); - plumed_dbg_assert( weight>=getTolerance() ); + double weight=myvals.get(0); + plumed_dbg_assert( weight>=getTolerance() ); // This deals with the value double dval, f=calcTransform( myvals.get(mycomp), dval ); - if( norm ){ - if( usetol && weight<getTolerance() ) return; - buffer[bufstart+1+nderivatives] += weight; - if( diffweight ) myvals.chainRule( 0, 1, 1, 0, 1.0, bufstart, buffer ); + if( norm ) { + if( usetol && weight<getTolerance() ) return; + buffer[bufstart+1+nderivatives] += weight; + if( diffweight ) myvals.chainRule( 0, 1, 1, 0, 1.0, bufstart, buffer ); } double contr=weight*f; if( usetol && contr<getTolerance() ) return; buffer[bufstart] += contr; - if( diffweight ) myvals.chainRule( 0, 0, 1, 0, f, bufstart, buffer ); + if( diffweight ) myvals.chainRule( 0, 0, 1, 0, f, bufstart, buffer ); if( getAction()->derivativesAreRequired() && fabs(dval)>0.0 ) myvals.chainRule( mycomp, 0, 1, 0, weight*dval, bufstart, buffer ); return; } -double FunctionVessel::calcTransform( const double& , double& ) const { - plumed_error(); return 1.0; +double FunctionVessel::calcTransform( const double&, double& ) const { + plumed_error(); return 1.0; } -void FunctionVessel::finish( const std::vector<double>& buffer ){ +void FunctionVessel::finish( const std::vector<double>& buffer ) { unsigned nderivatives=getFinalValue()->getNumberOfDerivatives(); - if( norm && diffweight ){ - double dv, val=finalTransform( buffer[bufstart], dv), weight=buffer[bufstart+1+nderivatives]; - getFinalValue()->set( val / weight ); - for(unsigned i=0;i<nderivatives;++i){ - getFinalValue()->addDerivative( i, buffer[bufstart+1+i]/weight - val*buffer[bufstart+1+nderivatives+1+i]/(weight*weight) ); - } - } else if( norm ){ - double dv, val=finalTransform( buffer[bufstart], dv), weight=buffer[bufstart+1+nderivatives]; - getFinalValue()->set( val / weight ); - for(unsigned i=0;i<nderivatives;++i) getFinalValue()->addDerivative( i, buffer[bufstart+1+i]/weight ); + if( norm && diffweight ) { + double dv, val=finalTransform( buffer[bufstart], dv), weight=buffer[bufstart+1+nderivatives]; + getFinalValue()->set( val / weight ); + for(unsigned i=0; i<nderivatives; ++i) { + getFinalValue()->addDerivative( i, buffer[bufstart+1+i]/weight - val*buffer[bufstart+1+nderivatives+1+i]/(weight*weight) ); + } + } else if( norm ) { + double dv, val=finalTransform( buffer[bufstart], dv), weight=buffer[bufstart+1+nderivatives]; + getFinalValue()->set( val / weight ); + for(unsigned i=0; i<nderivatives; ++i) getFinalValue()->addDerivative( i, buffer[bufstart+1+i]/weight ); } else { - double dv, val=finalTransform( buffer[bufstart], dv); getFinalValue()->set( val ); - for(unsigned i=0;i<nderivatives;++i) getFinalValue()->addDerivative( i, dv*buffer[bufstart+1+i] ); + double dv, val=finalTransform( buffer[bufstart], dv); getFinalValue()->set( val ); + for(unsigned i=0; i<nderivatives; ++i) getFinalValue()->addDerivative( i, dv*buffer[bufstart+1+i] ); } } -double FunctionVessel::finalTransform( const double& val, double& dv ){ +double FunctionVessel::finalTransform( const double& val, double& dv ) { dv=1.0; return val; } diff --git a/src/vesselbase/FunctionVessel.h b/src/vesselbase/FunctionVessel.h index 920d668b4..b6fd05d55 100644 --- a/src/vesselbase/FunctionVessel.h +++ b/src/vesselbase/FunctionVessel.h @@ -29,13 +29,13 @@ #include "core/Value.h" namespace PLMD { -namespace vesselbase{ +namespace vesselbase { /** \ingroup TOOLBOX Objects that inherit from FunctionVessel can be used (in tandem with PLMD::vesselbase::ActionWithVessel) to calculate functions of the form \f$\prod_k H_k[ \sum_j \prod_i g_i(x) ]\f$. They should take in a series of values -and return one single value. +and return one single value. */ class FunctionVessel : public ValueVessel { diff --git a/src/vesselbase/Highest.cpp b/src/vesselbase/Highest.cpp index 727a9fd95..437f681ec 100644 --- a/src/vesselbase/Highest.cpp +++ b/src/vesselbase/Highest.cpp @@ -23,7 +23,7 @@ #include "VesselRegister.h" namespace PLMD { -namespace vesselbase{ +namespace vesselbase { class Highest : public OrderingVessel { public: @@ -31,30 +31,30 @@ public: static void reserveKeyword( Keywords& keys ); explicit Highest( const VesselOptions& da ); std::string value_descriptor(); - bool compare( const double& , const double& ); + bool compare( const double&, const double& ); }; PLUMED_REGISTER_VESSEL(Highest,"HIGHEST") -void Highest::registerKeywords( Keywords& keys ){ +void Highest::registerKeywords( Keywords& keys ) { OrderingVessel::registerKeywords( keys ); } -void Highest::reserveKeyword( Keywords& keys ){ +void Highest::reserveKeyword( Keywords& keys ) { keys.reserve("vessel","HIGHEST","this flag allows you to recover the highest of these variables."); keys.addOutputComponent("highest","HIGHEST","the lowest of the quantitities calculated by this action"); } Highest::Highest( const VesselOptions& da ) : -OrderingVessel(da) + OrderingVessel(da) { } -std::string Highest::value_descriptor(){ +std::string Highest::value_descriptor() { return "the highest of the individual colvar values"; } -bool Highest::compare( const double& val1, const double& val2 ){ +bool Highest::compare( const double& val1, const double& val2 ) { return val1>val2; } diff --git a/src/vesselbase/Histogram.cpp b/src/vesselbase/Histogram.cpp index 2e3fae75d..eb91f0ce2 100644 --- a/src/vesselbase/Histogram.cpp +++ b/src/vesselbase/Histogram.cpp @@ -23,8 +23,8 @@ #include "VesselRegister.h" #include "ShortcutVessel.h" -namespace PLMD{ -namespace vesselbase{ +namespace PLMD { +namespace vesselbase { class Histogram : public ShortcutVessel { public: @@ -35,25 +35,25 @@ public: PLUMED_REGISTER_VESSEL(Histogram,"HISTOGRAM") -void Histogram::registerKeywords( Keywords& keys ){ +void Histogram::registerKeywords( Keywords& keys ) { ShortcutVessel::registerKeywords( keys ); HistogramBead::registerKeywords( keys ); keys.add("compulsory","NBINS","The number of equal width bins you want to divide the range into"); - keys.addFlag("NORM",false,"calculate the fraction of values rather than the number"); + keys.addFlag("NORM",false,"calculate the fraction of values rather than the number"); } -void Histogram::reserveKeyword( Keywords& keys ){ +void Histogram::reserveKeyword( Keywords& keys ) { keys.reserve("vessel","HISTOGRAM","calculate a discretized histogram of the distribution of values. " - "This shortcut allows you to calculates NBIN quantites like BETWEEN."); + "This shortcut allows you to calculates NBIN quantites like BETWEEN."); } Histogram::Histogram( const VesselOptions& da ): -ShortcutVessel(da) + ShortcutVessel(da) { bool norm; parseFlag("NORM",norm); std::string normstr=""; if(norm) normstr=" NORM"; std::vector<std::string> bins; HistogramBead::generateBins( getAllInput(), bins ); - for(unsigned i=0;i<bins.size();++i) addVessel("BETWEEN",bins[i] + normstr); + for(unsigned i=0; i<bins.size(); ++i) addVessel("BETWEEN",bins[i] + normstr); } } diff --git a/src/vesselbase/LessThan.cpp b/src/vesselbase/LessThan.cpp index 1e3c19bfa..7d1c69c71 100644 --- a/src/vesselbase/LessThan.cpp +++ b/src/vesselbase/LessThan.cpp @@ -23,34 +23,34 @@ #include "VesselRegister.h" namespace PLMD { -namespace vesselbase{ +namespace vesselbase { PLUMED_REGISTER_VESSEL(LessThan,"LESS_THAN") -void LessThan::registerKeywords( Keywords& keys ){ +void LessThan::registerKeywords( Keywords& keys ) { FunctionVessel::registerKeywords( keys ); SwitchingFunction::registerKeywords( keys ); } -void LessThan::reserveKeyword( Keywords& keys ){ +void LessThan::reserveKeyword( Keywords& keys ) { keys.reserve("vessel","LESS_THAN","calculate the number of variables less than a certain target value. " - "This quantity is calculated using \\f$\\sum_i \\sigma(s_i)\\f$, where \\f$\\sigma(s)\\f$ " - "is a \\ref switchingfunction."); - keys.addOutputComponent("lessthan","LESS_THAN","the number of values less than a target value. This is calculated using one of the " - "formula described in the description of the keyword so as to make it continuous. " - "You can calculate this quantity multiple times using different parameters."); + "This quantity is calculated using \\f$\\sum_i \\sigma(s_i)\\f$, where \\f$\\sigma(s)\\f$ " + "is a \\ref switchingfunction."); + keys.addOutputComponent("lessthan","LESS_THAN","the number of values less than a target value. This is calculated using one of the " + "formula described in the description of the keyword so as to make it continuous. " + "You can calculate this quantity multiple times using different parameters."); } LessThan::LessThan( const VesselOptions& da ) : -FunctionVessel(da) + FunctionVessel(da) { - usetol=true; + usetol=true; if( getAction()->isPeriodic() ) error("LESS_THAN is not a meaningful option for periodic variables"); - std::string errormsg; sf.set( getAllInput(), errormsg ); - if( errormsg.size()!=0 ) error( errormsg ); + std::string errormsg; sf.set( getAllInput(), errormsg ); + if( errormsg.size()!=0 ) error( errormsg ); } -std::string LessThan::value_descriptor(){ +std::string LessThan::value_descriptor() { return "the number of values less than " + sf.description(); } @@ -58,7 +58,7 @@ double LessThan::calcTransform( const double& val, double& dv ) const { double f = sf.calculate(val, dv); dv*=val; return f; } -double LessThan::getCutoff(){ +double LessThan::getCutoff() { return sf.get_dmax(); } diff --git a/src/vesselbase/LessThan.h b/src/vesselbase/LessThan.h index 3a624788e..f276f6e4a 100644 --- a/src/vesselbase/LessThan.h +++ b/src/vesselbase/LessThan.h @@ -27,14 +27,14 @@ #include "ActionWithVessel.h" namespace PLMD { -namespace vesselbase{ +namespace vesselbase { class LessThan : public FunctionVessel { private: SwitchingFunction sf; public: static void registerKeywords( Keywords& keys ); - static void reserveKeyword( Keywords& keys ); + static void reserveKeyword( Keywords& keys ); explicit LessThan( const VesselOptions& da ); std::string value_descriptor(); double calcTransform( const double& val, double& dv ) const ; diff --git a/src/vesselbase/Lowest.cpp b/src/vesselbase/Lowest.cpp index bf8c5e63a..9121543b7 100644 --- a/src/vesselbase/Lowest.cpp +++ b/src/vesselbase/Lowest.cpp @@ -23,7 +23,7 @@ #include "VesselRegister.h" namespace PLMD { -namespace vesselbase{ +namespace vesselbase { class Lowest : public OrderingVessel { public: @@ -31,30 +31,30 @@ public: static void reserveKeyword( Keywords& keys ); explicit Lowest( const VesselOptions& da ); std::string value_descriptor(); - bool compare( const double& , const double& ); + bool compare( const double&, const double& ); }; PLUMED_REGISTER_VESSEL(Lowest,"LOWEST") -void Lowest::registerKeywords( Keywords& keys ){ +void Lowest::registerKeywords( Keywords& keys ) { OrderingVessel::registerKeywords( keys ); } -void Lowest::reserveKeyword( Keywords& keys ){ +void Lowest::reserveKeyword( Keywords& keys ) { keys.reserve("vessel","LOWEST","this flag allows you to recover the lowest of these variables."); keys.addOutputComponent("lowest","LOWEST","the lowest of the quantitities calculated by this action"); } Lowest::Lowest( const VesselOptions& da ) : -OrderingVessel(da) + OrderingVessel(da) { } -std::string Lowest::value_descriptor(){ +std::string Lowest::value_descriptor() { return "the lowest of the individual colvar values"; } -bool Lowest::compare( const double& val1, const double& val2 ){ +bool Lowest::compare( const double& val1, const double& val2 ) { return val1<val2; } diff --git a/src/vesselbase/Max.cpp b/src/vesselbase/Max.cpp index 0f4d65409..d9b7b2c5a 100644 --- a/src/vesselbase/Max.cpp +++ b/src/vesselbase/Max.cpp @@ -24,7 +24,7 @@ #include "ActionWithVessel.h" namespace PLMD { -namespace vesselbase{ +namespace vesselbase { class Max : public FunctionVessel { private: @@ -40,23 +40,23 @@ public: PLUMED_REGISTER_VESSEL(Max,"MAX") -void Max::registerKeywords( Keywords& keys ){ +void Max::registerKeywords( Keywords& keys ) { FunctionVessel::registerKeywords( keys ); keys.add("compulsory","BETA","the value of beta for the equation in the manual"); } -void Max::reserveKeyword( Keywords& keys ){ +void Max::reserveKeyword( Keywords& keys ) { keys.reserve("vessel","MAX","calculate the maximum value. " - "To make this quantity continuous the maximum is calculated using " - "\\f$ \\textrm{max} = \\beta \\log \\sum_i \\exp\\left( \\frac{s_i}{\\beta}\\right) \\f$ " - "The value of \\f$\\beta\\f$ in this function is specified using (BETA=\\f$\\beta\\f$)"); + "To make this quantity continuous the maximum is calculated using " + "\\f$ \\textrm{max} = \\beta \\log \\sum_i \\exp\\left( \\frac{s_i}{\\beta}\\right) \\f$ " + "The value of \\f$\\beta\\f$ in this function is specified using (BETA=\\f$\\beta\\f$)"); keys.addOutputComponent("max","MAX","the maximum value. This is calculated using the formula described in the description of the " - "keyword so as to make it continuous."); + "keyword so as to make it continuous."); } Max::Max( const VesselOptions& da ) : -FunctionVessel(da) + FunctionVessel(da) { if( getAction()->isPeriodic() ) error("max is not a meaningful option for periodic variables"); parse("BETA",beta); @@ -64,7 +64,7 @@ FunctionVessel(da) if( diffweight ) error("can't calculate max if weight is differentiable"); } -std::string Max::value_descriptor(){ +std::string Max::value_descriptor() { std::string str_beta; Tools::convert( beta, str_beta ); return "the maximum value. Beta is equal to " + str_beta; } @@ -73,7 +73,7 @@ double Max::calcTransform( const double& val, double& dv ) const { double f = exp(val/beta); dv=f/beta; return f; } -double Max::finalTransform( const double& val, double& dv ){ +double Max::finalTransform( const double& val, double& dv ) { double dist=beta*std::log( val ); dv = beta/val; return dist; } diff --git a/src/vesselbase/Mean.cpp b/src/vesselbase/Mean.cpp index 9bcfe1aa7..d2979761b 100644 --- a/src/vesselbase/Mean.cpp +++ b/src/vesselbase/Mean.cpp @@ -37,24 +37,24 @@ public: PLUMED_REGISTER_VESSEL(Mean,"MEAN") -void Mean::registerKeywords( Keywords& keys ){ +void Mean::registerKeywords( Keywords& keys ) { FunctionVessel::registerKeywords(keys); } -void Mean::reserveKeyword( Keywords& keys ){ +void Mean::reserveKeyword( Keywords& keys ) { keys.reserve("vessel","MEAN","take the mean of these variables."); keys.addOutputComponent("mean","MEAN","the mean value. The output component can be refererred to elsewhere in the input " - "file by using the label.mean"); + "file by using the label.mean"); } Mean::Mean( const vesselbase::VesselOptions& da ) : -FunctionVessel(da) + FunctionVessel(da) { if( getAction()->isPeriodic() ) error("MEAN cannot be used with periodic variables"); norm=true; // Makes sure we calculate the average } -std::string Mean::value_descriptor(){ +std::string Mean::value_descriptor() { return "the mean value"; } diff --git a/src/vesselbase/Min.cpp b/src/vesselbase/Min.cpp index 73230f9c4..989ee34c6 100644 --- a/src/vesselbase/Min.cpp +++ b/src/vesselbase/Min.cpp @@ -24,7 +24,7 @@ #include "ActionWithVessel.h" namespace PLMD { -namespace vesselbase{ +namespace vesselbase { class Min : public FunctionVessel { private: @@ -40,22 +40,22 @@ public: PLUMED_REGISTER_VESSEL(Min,"MIN") -void Min::registerKeywords( Keywords& keys ){ +void Min::registerKeywords( Keywords& keys ) { FunctionVessel::registerKeywords( keys ); keys.add("compulsory","BETA","the value of beta for the equation in the manual"); } -void Min::reserveKeyword( Keywords& keys ){ +void Min::reserveKeyword( Keywords& keys ) { keys.reserve("vessel","MIN","calculate the minimum value. " - "To make this quantity continuous the minimum is calculated using " - "\\f$ \\textrm{min} = \\frac{\\beta}{ \\log \\sum_i \\exp\\left( \\frac{\\beta}{s_i} \\right) } \\f$ " - "The value of \\f$\\beta\\f$ in this function is specified using (BETA=\\f$\\beta\\f$)"); + "To make this quantity continuous the minimum is calculated using " + "\\f$ \\textrm{min} = \\frac{\\beta}{ \\log \\sum_i \\exp\\left( \\frac{\\beta}{s_i} \\right) } \\f$ " + "The value of \\f$\\beta\\f$ in this function is specified using (BETA=\\f$\\beta\\f$)"); keys.addOutputComponent("min","MIN","the minimum value. This is calculated using the formula described in the description of the " - "keyword so as to make it continuous."); + "keyword so as to make it continuous."); } Min::Min( const VesselOptions& da ) : -FunctionVessel(da) + FunctionVessel(da) { if( getAction()->isPeriodic() ) error("min is not a meaningful option for periodic variables"); parse("BETA",beta); @@ -63,17 +63,17 @@ FunctionVessel(da) if( diffweight ) error("can't calculate min if weight is differentiable"); } -std::string Min::value_descriptor(){ +std::string Min::value_descriptor() { std::string str_beta; Tools::convert( beta, str_beta ); return "the minimum value. Beta is equal to " + str_beta; } double Min::calcTransform( const double& val, double& dv ) const { double f = exp(beta/val); dv=f/(val*val); - return f; + return f; } -double Min::finalTransform( const double& val, double& dv ){ +double Min::finalTransform( const double& val, double& dv ) { double dist=beta/std::log( val ); dv = dist*dist/val; return dist; } diff --git a/src/vesselbase/Moments.cpp b/src/vesselbase/Moments.cpp index dc449b57f..84d7e3919 100644 --- a/src/vesselbase/Moments.cpp +++ b/src/vesselbase/Moments.cpp @@ -24,10 +24,10 @@ #include "ActionWithVessel.h" namespace PLMD { -namespace vesselbase{ +namespace vesselbase { -// This is not the most efficient implementation -// The calculation of all the colvars is parallelized +// This is not the most efficient implementation +// The calculation of all the colvars is parallelized // but the loops for calculating moments are not // Feel free to reimplement this if you know how class Moments : public StoreDataVessel { @@ -46,109 +46,109 @@ public: PLUMED_REGISTER_VESSEL(Moments,"MOMENTS") -void Moments::registerKeywords( Keywords& keys ){ +void Moments::registerKeywords( Keywords& keys ) { StoreDataVessel::registerKeywords( keys ); } -void Moments::reserveKeyword( Keywords& keys ){ - keys.reserve("optional","MOMENTS","calculate the moments of the distribution of collective variables. " - "The \\f$m\\f$th moment of a distribution is calculated using \\f$\\frac{1}{N} \\sum_{i=1}^N ( s_i - \\overline{s} )^m \\f$, where \\f$\\overline{s}\\f$ is " - "the average for the distribution. The moments keyword takes a lists of integers as input or a range. Each integer is a value of \\f$m\\f$. The final " - "calculated values can be referenced using moment-\\f$m\\f$."); +void Moments::reserveKeyword( Keywords& keys ) { + keys.reserve("optional","MOMENTS","calculate the moments of the distribution of collective variables. " + "The \\f$m\\f$th moment of a distribution is calculated using \\f$\\frac{1}{N} \\sum_{i=1}^N ( s_i - \\overline{s} )^m \\f$, where \\f$\\overline{s}\\f$ is " + "the average for the distribution. The moments keyword takes a lists of integers as input or a range. Each integer is a value of \\f$m\\f$. The final " + "calculated values can be referenced using moment-\\f$m\\f$."); keys.reset_style("MOMENTS","vessel"); keys.addOutputComponent("moment","MOMENTS","the central moments of the distribution of values. The second moment " - "would be referenced elsewhere in the input file using " - "<em>label</em>.moment-2, the third as <em>label</em>.moment-3, etc."); + "would be referenced elsewhere in the input file using " + "<em>label</em>.moment-2, the third as <em>label</em>.moment-3, etc."); } Moments::Moments( const vesselbase::VesselOptions& da) : -StoreDataVessel(da) + StoreDataVessel(da) { - ActionWithValue* a=dynamic_cast<ActionWithValue*>( getAction() ); - plumed_massert(a,"cannot create passable values as base action does not inherit from ActionWithValue"); - - std::vector<std::string> moments=Tools::getWords(getAllInput(),"\t\n ,"); - Tools::interpretRanges(moments); unsigned nn; - for(unsigned i=0;i<moments.size();++i){ - a->addComponentWithDerivatives( "moment-" + moments[i] ); - a->componentIsNotPeriodic( "moment-" + moments[i] ); - value_out.push_back( a->copyOutput( a->getNumberOfComponents()-1 ) ); - Tools::convert( moments[i], nn ); - if( nn<2 ) error("moments are only possible for m>=2" ); - powers.push_back( nn ); std::string num; Tools::convert(powers[i],num); - } + ActionWithValue* a=dynamic_cast<ActionWithValue*>( getAction() ); + plumed_massert(a,"cannot create passable values as base action does not inherit from ActionWithValue"); + + std::vector<std::string> moments=Tools::getWords(getAllInput(),"\t\n ,"); + Tools::interpretRanges(moments); unsigned nn; + for(unsigned i=0; i<moments.size(); ++i) { + a->addComponentWithDerivatives( "moment-" + moments[i] ); + a->componentIsNotPeriodic( "moment-" + moments[i] ); + value_out.push_back( a->copyOutput( a->getNumberOfComponents()-1 ) ); + Tools::convert( moments[i], nn ); + if( nn<2 ) error("moments are only possible for m>=2" ); + powers.push_back( nn ); std::string num; Tools::convert(powers[i],num); + } } -void Moments::resize(){ - StoreDataVessel::resize(); +void Moments::resize() { + StoreDataVessel::resize(); } -std::string Moments::description(){ - std::string descri, num; - Tools::convert(powers[0],num); - descri = "value " + getAction()->getLabel() + "." + "moment-" + num + " contains the " + num + "th moment of the distribution"; - for(unsigned i=1;i<powers.size();++i){ - Tools::convert(powers[i],num); - descri = descri + "\n value " + getAction()->getLabel() + "." + "moment-" + num + " contains the " + num + "th moment of the distribution"; - } - return descri; +std::string Moments::description() { + std::string descri, num; + Tools::convert(powers[0],num); + descri = "value " + getAction()->getLabel() + "." + "moment-" + num + " contains the " + num + "th moment of the distribution"; + for(unsigned i=1; i<powers.size(); ++i) { + Tools::convert(powers[i],num); + descri = descri + "\n value " + getAction()->getLabel() + "." + "moment-" + num + " contains the " + num + "th moment of the distribution"; + } + return descri; } -void Moments::finish( const std::vector<double>& buffer ){ +void Moments::finish( const std::vector<double>& buffer ) { StoreDataVessel::finish( buffer ); const double pi=3.141592653589793238462643383279502884197169399375105820974944592307; - unsigned nvals=getAction()->getFullNumberOfTasks(); + unsigned nvals=getAction()->getFullNumberOfTasks(); double mean=0; Value myvalue; - if( getAction()->isPeriodic() ){ - std::string str_min, str_max; getAction()->retrieveDomain( str_min, str_max ); - double pfactor, min, max; Tools::convert(str_min,min); Tools::convert(str_max,max); - pfactor = 2*pi / ( max-min ); myvalue.setDomain( str_min, str_max ); - double sinsum=0, cossum=0, val; - for(unsigned i=0;i<nvals;++i){ val=pfactor*( buffer[bufstart + i*nspace*vecsize+nspace] - min ); sinsum+=sin(val); cossum+=cos(val); } - mean = 0.5 + atan2( sinsum / static_cast<double>( nvals ) , cossum / static_cast<double>( nvals ) ) / (2*pi); - mean = min + (max-min)*mean; + if( getAction()->isPeriodic() ) { + std::string str_min, str_max; getAction()->retrieveDomain( str_min, str_max ); + double pfactor, min, max; Tools::convert(str_min,min); Tools::convert(str_max,max); + pfactor = 2*pi / ( max-min ); myvalue.setDomain( str_min, str_max ); + double sinsum=0, cossum=0, val; + for(unsigned i=0; i<nvals; ++i) { val=pfactor*( buffer[bufstart + i*nspace*vecsize+nspace] - min ); sinsum+=sin(val); cossum+=cos(val); } + mean = 0.5 + atan2( sinsum / static_cast<double>( nvals ), cossum / static_cast<double>( nvals ) ) / (2*pi); + mean = min + (max-min)*mean; } else { - for(unsigned i=0;i<nvals;++i) mean+=buffer[bufstart + i*nspace*vecsize+nspace]; - mean/=static_cast<double>( nvals ); myvalue.setNotPeriodic(); + for(unsigned i=0; i<nvals; ++i) mean+=buffer[bufstart + i*nspace*vecsize+nspace]; + mean/=static_cast<double>( nvals ); myvalue.setNotPeriodic(); } - for(unsigned npow=0;npow<powers.size();++npow){ - double dev1=0; - if( value_out[0]->getNumberOfDerivatives()>0 ){ - for(unsigned i=0;i<nvals;++i) dev1+=pow( myvalue.difference( mean, buffer[bufstart + i*nspace*vecsize+nspace] ), powers[npow] - 1 ); - dev1/=static_cast<double>( nvals ); - } - - double moment=0; - MultiValue myvals( getNumberOfComponents(), getAction()->getNumberOfDerivatives() ); myvals.clearAll(); - for(unsigned i=0;i<nvals;++i){ - double tmp=myvalue.difference( mean, buffer[bufstart + i*nspace*vecsize+nspace] ); - moment+=pow( tmp, powers[npow] ); - if( value_out[npow]->getNumberOfDerivatives() ){ - double pref=pow( tmp, powers[npow] - 1 ) - dev1; - retrieveDerivatives( i, false, myvals ); - for(unsigned j=0;j<myvals.getNumberActive();++j){ - unsigned jatom=myvals.getActiveIndex(j); - value_out[npow]->addDerivative(jatom, pref*myvals.getDerivative( 1, jatom ) ); - } - myvals.clearAll(); - } - } - if( value_out[npow]->getNumberOfDerivatives()>0 ) value_out[npow]->chainRule( powers[npow] / static_cast<double>( nvals ) ); - value_out[npow]->set( moment / static_cast<double>( nvals ) ); + for(unsigned npow=0; npow<powers.size(); ++npow) { + double dev1=0; + if( value_out[0]->getNumberOfDerivatives()>0 ) { + for(unsigned i=0; i<nvals; ++i) dev1+=pow( myvalue.difference( mean, buffer[bufstart + i*nspace*vecsize+nspace] ), powers[npow] - 1 ); + dev1/=static_cast<double>( nvals ); + } + + double moment=0; + MultiValue myvals( getNumberOfComponents(), getAction()->getNumberOfDerivatives() ); myvals.clearAll(); + for(unsigned i=0; i<nvals; ++i) { + double tmp=myvalue.difference( mean, buffer[bufstart + i*nspace*vecsize+nspace] ); + moment+=pow( tmp, powers[npow] ); + if( value_out[npow]->getNumberOfDerivatives() ) { + double pref=pow( tmp, powers[npow] - 1 ) - dev1; + retrieveDerivatives( i, false, myvals ); + for(unsigned j=0; j<myvals.getNumberActive(); ++j) { + unsigned jatom=myvals.getActiveIndex(j); + value_out[npow]->addDerivative(jatom, pref*myvals.getDerivative( 1, jatom ) ); + } + myvals.clearAll(); + } + } + if( value_out[npow]->getNumberOfDerivatives()>0 ) value_out[npow]->chainRule( powers[npow] / static_cast<double>( nvals ) ); + value_out[npow]->set( moment / static_cast<double>( nvals ) ); } } -bool Moments::applyForce( std::vector<double>& forces ){ +bool Moments::applyForce( std::vector<double>& forces ) { std::vector<double> tmpforce( forces.size() ); forces.assign(forces.size(),0.0); bool wasforced=false; - for(unsigned i=0;i<value_out.size();++i){ - if( value_out[i]->applyForce( tmpforce ) ){ - wasforced=true; - for(unsigned j=0;j<forces.size();++j) forces[j]+=tmpforce[j]; - } + for(unsigned i=0; i<value_out.size(); ++i) { + if( value_out[i]->applyForce( tmpforce ) ) { + wasforced=true; + for(unsigned j=0; j<forces.size(); ++j) forces[j]+=tmpforce[j]; + } } return wasforced; } diff --git a/src/vesselbase/MoreThan.cpp b/src/vesselbase/MoreThan.cpp index a4b0ff8f1..6a98e3bae 100644 --- a/src/vesselbase/MoreThan.cpp +++ b/src/vesselbase/MoreThan.cpp @@ -26,7 +26,7 @@ #include "ActionWithVessel.h" namespace PLMD { -namespace vesselbase{ +namespace vesselbase { class MoreThan : public FunctionVessel { private: @@ -41,35 +41,35 @@ public: PLUMED_REGISTER_VESSEL(MoreThan,"MORE_THAN") -void MoreThan::registerKeywords( Keywords& keys ){ +void MoreThan::registerKeywords( Keywords& keys ) { FunctionVessel::registerKeywords( keys ); SwitchingFunction::registerKeywords( keys ); } -void MoreThan::reserveKeyword( Keywords& keys ){ +void MoreThan::reserveKeyword( Keywords& keys ) { keys.reserve("vessel","MORE_THAN","calculate the number of variables more than a certain target value. " - "This quantity is calculated using \\f$\\sum_i 1.0 - \\sigma(s_i)\\f$, where \\f$\\sigma(s)\\f$ " - "is a \\ref switchingfunction."); + "This quantity is calculated using \\f$\\sum_i 1.0 - \\sigma(s_i)\\f$, where \\f$\\sigma(s)\\f$ " + "is a \\ref switchingfunction."); keys.addOutputComponent("morethan","MORE_THAN","the number of values more than a target value. This is calculated using one of the " - "formula described in the description of the keyword so as to make it continuous. " - "You can calculate this quantity multiple times using different parameters."); + "formula described in the description of the keyword so as to make it continuous. " + "You can calculate this quantity multiple times using different parameters."); } MoreThan::MoreThan( const VesselOptions& da ) : -FunctionVessel(da) + FunctionVessel(da) { - usetol=true; + usetol=true; if( getAction()->isPeriodic() ) error("more than is not a meaningful option for periodic variables"); std::string errormsg; sf.set( getAllInput(), errormsg ); if( errormsg.size()!=0 ) error( errormsg ); } -std::string MoreThan::value_descriptor(){ +std::string MoreThan::value_descriptor() { return "the number of values more than " + sf.description(); } double MoreThan::calcTransform( const double& val, double& dv ) const { - double f = 1.0 - sf.calculate(val, dv); dv*=-val; return f; + double f = 1.0 - sf.calculate(val, dv); dv*=-val; return f; } } diff --git a/src/vesselbase/OrderingVessel.cpp b/src/vesselbase/OrderingVessel.cpp index 952dcb85d..4eab91788 100644 --- a/src/vesselbase/OrderingVessel.cpp +++ b/src/vesselbase/OrderingVessel.cpp @@ -23,47 +23,47 @@ #include "core/ActionWithValue.h" namespace PLMD { -namespace vesselbase{ +namespace vesselbase { -void OrderingVessel::registerKeywords( Keywords& keys ){ +void OrderingVessel::registerKeywords( Keywords& keys ) { ValueVessel::registerKeywords( keys ); } OrderingVessel::OrderingVessel( const VesselOptions& da ) : -ValueVessel(da) + ValueVessel(da) { mydata = getAction()->buildDataStashes( NULL ); - for(unsigned i=0;i<getAction()->getNumberOfVessels();++i){ - if( getAction()->getPntrToVessel(i)->getName()==getName() ) - error("calculating lowest/highest value multiple times serves no purpose"); + for(unsigned i=0; i<getAction()->getNumberOfVessels(); ++i) { + if( getAction()->getPntrToVessel(i)->getName()==getName() ) + error("calculating lowest/highest value multiple times serves no purpose"); } } -void OrderingVessel::resize(){ - resizeBuffer( 0 ); +void OrderingVessel::resize() { + resizeBuffer( 0 ); if( getAction()->derivativesAreRequired() ) getFinalValue()->resizeDerivatives( getAction()->getNumberOfDerivatives() ); } -void OrderingVessel::finish( const std::vector<double>& buffer ){ +void OrderingVessel::finish( const std::vector<double>& buffer ) { std::vector<double> values( getAction()->getNumberOfQuantities() ); mydata->retrieveSequentialValue( 0, false, values ); double min=values[mycomp]; unsigned mini=getAction()->getPositionInFullTaskList(0); - for(unsigned i=1;i<mydata->getNumberOfStoredValues();++i){ - mydata->retrieveSequentialValue( i, false, values ); - double newval = values[mycomp]; - if( compare( newval, min ) ){ min=newval; mini=getAction()->getPositionInFullTaskList(i); } + for(unsigned i=1; i<mydata->getNumberOfStoredValues(); ++i) { + mydata->retrieveSequentialValue( i, false, values ); + double newval = values[mycomp]; + if( compare( newval, min ) ) { min=newval; mini=getAction()->getPositionInFullTaskList(i); } } setOutputValue( min ); - if( getAction()->derivativesAreRequired() ){ - MultiValue myvals( getAction()->getNumberOfQuantities(), getAction()->getNumberOfDerivatives() ); - mydata->retrieveDerivatives( mini, false, myvals ); Value* fval=getFinalValue(); - for(unsigned i=0;i<myvals.getNumberActive();++i){ - unsigned ider=myvals.getActiveIndex(i); - fval->setDerivative( ider, myvals.getDerivative(mycomp,ider) ); - } + if( getAction()->derivativesAreRequired() ) { + MultiValue myvals( getAction()->getNumberOfQuantities(), getAction()->getNumberOfDerivatives() ); + mydata->retrieveDerivatives( mini, false, myvals ); Value* fval=getFinalValue(); + for(unsigned i=0; i<myvals.getNumberActive(); ++i) { + unsigned ider=myvals.getActiveIndex(i); + fval->setDerivative( ider, myvals.getDerivative(mycomp,ider) ); + } } } diff --git a/src/vesselbase/OrderingVessel.h b/src/vesselbase/OrderingVessel.h index c3ec6d13c..6e8fb93cc 100644 --- a/src/vesselbase/OrderingVessel.h +++ b/src/vesselbase/OrderingVessel.h @@ -30,7 +30,7 @@ #include "core/Value.h" namespace PLMD { -namespace vesselbase{ +namespace vesselbase { class OrderingVessel : public ValueVessel { private: @@ -41,7 +41,7 @@ public: void resize(); void calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const {} void finish( const std::vector<double>& buffer ); - virtual bool compare( const double& , const double& )=0; + virtual bool compare( const double&, const double& )=0; }; } diff --git a/src/vesselbase/ShortcutVessel.cpp b/src/vesselbase/ShortcutVessel.cpp index 41e64a549..fc3be38c6 100644 --- a/src/vesselbase/ShortcutVessel.cpp +++ b/src/vesselbase/ShortcutVessel.cpp @@ -22,23 +22,23 @@ #include "ShortcutVessel.h" #include "ActionWithVessel.h" -namespace PLMD{ -namespace vesselbase{ +namespace PLMD { +namespace vesselbase { -void ShortcutVessel::registerKeywords( Keywords& keys ){ +void ShortcutVessel::registerKeywords( Keywords& keys ) { Vessel::registerKeywords( keys ); keys.remove("LABEL"); plumed_assert( keys.size()==0 ); } ShortcutVessel::ShortcutVessel( const VesselOptions& da): -Vessel(da) + Vessel(da) { } -void ShortcutVessel::addVessel( const std::string& name, const std::string& input ){ +void ShortcutVessel::addVessel( const std::string& name, const std::string& input ) { unsigned numlab=1; - for(unsigned i=0;i<(getAction()->functions).size();++i){ - if( (getAction()->functions[i])->getName()==name ) numlab++; + for(unsigned i=0; i<(getAction()->functions).size(); ++i) { + if( (getAction()->functions[i])->getName()==name ) numlab++; } getAction()->addVessel( name, input, numlab ); } diff --git a/src/vesselbase/ShortcutVessel.h b/src/vesselbase/ShortcutVessel.h index f84555205..c6e66d76c 100644 --- a/src/vesselbase/ShortcutVessel.h +++ b/src/vesselbase/ShortcutVessel.h @@ -29,19 +29,19 @@ #include "core/Value.h" namespace PLMD { -namespace vesselbase{ +namespace vesselbase { class ShortcutVessel : public Vessel { protected: - void addVessel( const std::string& name, const std::string& intput ); + void addVessel( const std::string& name, const std::string& intput ); public: static void registerKeywords( Keywords& keys ); explicit ShortcutVessel( const VesselOptions& ); - std::string description(){ return ""; } - void resize(){ plumed_error(); } + std::string description() { return ""; } + void resize() { plumed_error(); } void calculate( const unsigned& taskCode, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_index ) const { plumed_error(); } - void finish( const std::vector<double>& buffer ){ plumed_error(); } - bool applyForce( std::vector<double>& forces ){ plumed_error(); } + void finish( const std::vector<double>& buffer ) { plumed_error(); } + bool applyForce( std::vector<double>& forces ) { plumed_error(); } }; } diff --git a/src/vesselbase/StoreDataVessel.cpp b/src/vesselbase/StoreDataVessel.cpp index 13f4c9ab6..a89c50d14 100644 --- a/src/vesselbase/StoreDataVessel.cpp +++ b/src/vesselbase/StoreDataVessel.cpp @@ -24,38 +24,38 @@ namespace PLMD { namespace vesselbase { -void StoreDataVessel::registerKeywords( Keywords& keys ){ +void StoreDataVessel::registerKeywords( Keywords& keys ) { Vessel::registerKeywords(keys); keys.remove("LABEL"); } StoreDataVessel::StoreDataVessel( const VesselOptions& da ): -Vessel(da), -max_lowmem_stash(3), -vecsize(0), -nspace(0) + Vessel(da), + max_lowmem_stash(3), + vecsize(0), + nspace(0) { ActionWithValue* myval=dynamic_cast<ActionWithValue*>( getAction() ); if( !myval ) hasderiv=false; else hasderiv=!myval->doNotCalculateDerivatives(); } -void StoreDataVessel::addActionThatUses( ActionWithVessel* actionThatUses ){ +void StoreDataVessel::addActionThatUses( ActionWithVessel* actionThatUses ) { userActions.push_back( actionThatUses ); } -void StoreDataVessel::resize(){ +void StoreDataVessel::resize() { vecsize=getAction()->getNumberOfQuantities(); plumed_dbg_assert( vecsize>0 ); - if( getAction()->lowmem || !getAction()->derivativesAreRequired() ){ - nspace = 1; - active_der.resize( max_lowmem_stash * ( 1 + getAction()->getNumberOfDerivatives() ) ); + if( getAction()->lowmem || !getAction()->derivativesAreRequired() ) { + nspace = 1; + active_der.resize( max_lowmem_stash * ( 1 + getAction()->getNumberOfDerivatives() ) ); } else { - if( getAction()->getNumberOfDerivatives()>getAction()->maxderivatives ){ - error("not enough memory to store derivatives for action " + getAction()->getLabel() + " use LOWMEM option"); - } - nspace = 1 + getAction()->maxderivatives; - active_der.resize( getNumberOfStoredValues() * ( 1 + getAction()->maxderivatives ) ); + if( getAction()->getNumberOfDerivatives()>getAction()->maxderivatives ) { + error("not enough memory to store derivatives for action " + getAction()->getLabel() + " use LOWMEM option"); + } + nspace = 1 + getAction()->maxderivatives; + active_der.resize( getNumberOfStoredValues() * ( 1 + getAction()->maxderivatives ) ); } resizeBuffer( getNumberOfStoredValues()*vecsize*nspace ); local_buffer.resize( getNumberOfStoredValues()*vecsize*nspace ); @@ -64,9 +64,9 @@ void StoreDataVessel::resize(){ void StoreDataVessel::storeValues( const unsigned& myelem, MultiValue& myvals, std::vector<double>& buffer ) const { plumed_dbg_assert( vecsize>0 ); unsigned jelem = getAction()->getPositionInCurrentTaskList( myelem ); plumed_dbg_assert( jelem<getNumberOfStoredValues() ); - unsigned ibuf = bufstart + jelem * vecsize * nspace; - for(unsigned icomp=0;icomp<vecsize;++icomp){ - buffer[ibuf] += myvals.get(icomp); ibuf+=nspace; + unsigned ibuf = bufstart + jelem * vecsize * nspace; + for(unsigned icomp=0; icomp<vecsize; ++icomp) { + buffer[ibuf] += myvals.get(icomp); ibuf+=nspace; } } @@ -74,38 +74,38 @@ void StoreDataVessel::storeDerivatives( const unsigned& myelem, MultiValue& myva plumed_dbg_assert( vecsize>0 && getAction()->derivativesAreRequired() && myelem<getAction()->getFullNumberOfTasks() ); unsigned jelem = getAction()->getPositionInCurrentTaskList( myelem ); - if( getAction()->getFullNumberOfTasks()==getNumberOfStoredValues() ){ - der_list[jelem]=myvals.getNumberActive(); - unsigned kder = getNumberOfStoredValues() + jelem * ( nspace - 1 ); - for(unsigned j=0;j<myvals.getNumberActive();++j){ der_list[kder] = myvals.getActiveIndex(j); kder++; } + if( getAction()->getFullNumberOfTasks()==getNumberOfStoredValues() ) { + der_list[jelem]=myvals.getNumberActive(); + unsigned kder = getNumberOfStoredValues() + jelem * ( nspace - 1 ); + for(unsigned j=0; j<myvals.getNumberActive(); ++j) { der_list[kder] = myvals.getActiveIndex(j); kder++; } } else { - // This ensures that active indices are gathered correctly if - // we have multiple tasks contributing to a stored quantity - unsigned kder = getNumberOfStoredValues() + jelem * ( nspace - 1 ); - for(unsigned j=0;j<myvals.getNumberActive();++j){ - bool found=false; unsigned jder = myvals.getActiveIndex(j); - for(unsigned k=0;k<der_list[jelem];++k){ - if( der_list[kder+k]==jder ){ found=true; break; } - } - if(!found){ der_list[kder+der_list[jelem]]=jder; der_list[jelem]++; } + // This ensures that active indices are gathered correctly if + // we have multiple tasks contributing to a stored quantity + unsigned kder = getNumberOfStoredValues() + jelem * ( nspace - 1 ); + for(unsigned j=0; j<myvals.getNumberActive(); ++j) { + bool found=false; unsigned jder = myvals.getActiveIndex(j); + for(unsigned k=0; k<der_list[jelem]; ++k) { + if( der_list[kder+k]==jder ) { found=true; break; } } + if(!found) { der_list[kder+der_list[jelem]]=jder; der_list[jelem]++; } + } } - // Store the values of the components and the derivatives - for(unsigned icomp=0;icomp<vecsize;++icomp){ - unsigned ibuf = bufstart + jelem * ( vecsize*nspace ) + icomp*nspace + 1; - for(unsigned j=0;j<myvals.getNumberActive();++j){ - unsigned jder=myvals.getActiveIndex(j); - buffer[ibuf] += myvals.getDerivative( icomp, jder ); ibuf++; - } + // Store the values of the components and the derivatives + for(unsigned icomp=0; icomp<vecsize; ++icomp) { + unsigned ibuf = bufstart + jelem * ( vecsize*nspace ) + icomp*nspace + 1; + for(unsigned j=0; j<myvals.getNumberActive(); ++j) { + unsigned jder=myvals.getActiveIndex(j); + buffer[ibuf] += myvals.getDerivative( icomp, jder ); ibuf++; + } } } void StoreDataVessel::retrieveSequentialValue( const unsigned& jelem, const bool& normed, std::vector<double>& values ) const { plumed_assert( values.size()==vecsize ); unsigned ibuf = jelem * vecsize * nspace; - for(unsigned i=0;i<vecsize;++i){ values[i]=local_buffer[ibuf]; ibuf+=nspace; } - if( normed && values.size()>2 ) getAction()->normalizeVector( values ); + for(unsigned i=0; i<vecsize; ++i) { values[i]=local_buffer[ibuf]; ibuf+=nspace; } + if( normed && values.size()>2 ) getAction()->normalizeVector( values ); } void StoreDataVessel::retrieveValueWithIndex( const unsigned& myelem, const bool& normed, std::vector<double>& values ) const { @@ -119,60 +119,60 @@ double StoreDataVessel::retrieveWeightWithIndex( const unsigned& myelem ) const unsigned jelem = getStoreIndex( myelem ); unsigned ibuf = jelem * vecsize * nspace; return local_buffer[ibuf]; } -void StoreDataVessel::retrieveDerivatives( const unsigned& myelem, const bool& normed, MultiValue& myvals ){ +void StoreDataVessel::retrieveDerivatives( const unsigned& myelem, const bool& normed, MultiValue& myvals ) { plumed_dbg_assert( myvals.getNumberOfValues()==vecsize && myvals.getNumberOfDerivatives()==getAction()->getNumberOfDerivatives() ); myvals.clearAll(); - if( getAction()->lowmem ){ - recalculateStoredQuantity( myelem, myvals ); - if( normed ) getAction()->normalizeVectorDerivatives( myvals ); + if( getAction()->lowmem ) { + recalculateStoredQuantity( myelem, myvals ); + if( normed ) getAction()->normalizeVectorDerivatives( myvals ); } else { - unsigned jelem = getAction()->getPositionInCurrentTaskList( myelem ); - // Retrieve the derivatives for elements 0 and 1 - weight and norm - for(unsigned icomp=0;icomp<vecsize;++icomp){ - unsigned ibuf = jelem * ( vecsize*nspace ) + icomp*nspace + 1; - unsigned kder = getNumberOfStoredValues() + jelem * ( nspace - 1 ); - for(unsigned j=0;j<active_der[jelem];++j){ - myvals.addDerivative( icomp, active_der[kder], local_buffer[ibuf] ); - kder++; ibuf++; - } - } - if( normed ) getAction()->normalizeVectorDerivatives( myvals ); - // Now ensure appropriate parts of list are activated - myvals.emptyActiveMembers(); + unsigned jelem = getAction()->getPositionInCurrentTaskList( myelem ); + // Retrieve the derivatives for elements 0 and 1 - weight and norm + for(unsigned icomp=0; icomp<vecsize; ++icomp) { + unsigned ibuf = jelem * ( vecsize*nspace ) + icomp*nspace + 1; unsigned kder = getNumberOfStoredValues() + jelem * ( nspace - 1 ); - for(unsigned j=0;j<active_der[jelem];++j){ myvals.putIndexInActiveArray( active_der[kder] ); kder++; } - myvals.sortActiveList(); - } + for(unsigned j=0; j<active_der[jelem]; ++j) { + myvals.addDerivative( icomp, active_der[kder], local_buffer[ibuf] ); + kder++; ibuf++; + } + } + if( normed ) getAction()->normalizeVectorDerivatives( myvals ); + // Now ensure appropriate parts of list are activated + myvals.emptyActiveMembers(); + unsigned kder = getNumberOfStoredValues() + jelem * ( nspace - 1 ); + for(unsigned j=0; j<active_der[jelem]; ++j) { myvals.putIndexInActiveArray( active_der[kder] ); kder++; } + myvals.sortActiveList(); + } } void StoreDataVessel::calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const { - if( myvals.get(0)>epsilon ){ - storeValues( current, myvals, buffer ); - if( !(getAction()->lowmem) && getAction()->derivativesAreRequired() ) storeDerivatives( current, myvals, buffer, der_list ); - } + if( myvals.get(0)>epsilon ) { + storeValues( current, myvals, buffer ); + if( !(getAction()->lowmem) && getAction()->derivativesAreRequired() ) storeDerivatives( current, myvals, buffer, der_list ); + } return; } -void StoreDataVessel::finish( const std::vector<double>& buffer ){ +void StoreDataVessel::finish( const std::vector<double>& buffer ) { // Store the buffer locally - for(unsigned i=0;i<local_buffer.size();++i) local_buffer[i]=buffer[bufstart+i]; + for(unsigned i=0; i<local_buffer.size(); ++i) local_buffer[i]=buffer[bufstart+i]; } -void StoreDataVessel::setActiveValsAndDerivatives( const std::vector<unsigned>& der_index ){ - if( !getAction()->lowmem && getAction()->derivativesAreRequired() ){ - for(unsigned i=0;i<der_index.size();++i) active_der[i]=der_index[i]; +void StoreDataVessel::setActiveValsAndDerivatives( const std::vector<unsigned>& der_index ) { + if( !getAction()->lowmem && getAction()->derivativesAreRequired() ) { + for(unsigned i=0; i<der_index.size(); ++i) active_der[i]=der_index[i]; } } -void StoreDataVessel::resizeTemporyMultiValues( const unsigned& nvals ){ - for(unsigned i=0;i<nvals;++i) my_tmp_vals.push_back( MultiValue(0,0) ); +void StoreDataVessel::resizeTemporyMultiValues( const unsigned& nvals ) { + for(unsigned i=0; i<nvals; ++i) my_tmp_vals.push_back( MultiValue(0,0) ); } -MultiValue& StoreDataVessel::getTemporyMultiValue( const unsigned& ind ){ +MultiValue& StoreDataVessel::getTemporyMultiValue( const unsigned& ind ) { plumed_dbg_assert( ind<my_tmp_vals.size() ); return my_tmp_vals[ind]; } diff --git a/src/vesselbase/StoreDataVessel.h b/src/vesselbase/StoreDataVessel.h index ae75aa6ee..1b8fafef4 100644 --- a/src/vesselbase/StoreDataVessel.h +++ b/src/vesselbase/StoreDataVessel.h @@ -32,36 +32,36 @@ namespace vesselbase { /** \ingroup TOOLBOX -Objects that inherit from FunctionVessel can be used (in tandem with PLMD::vesselbase::ActionWithVessel) -to store values and derivatives for a set of scalars or vectors that are calculated by a -PLMD::vesselbase::ActionWithVessel. Functions of these stored quantities can then be calculated in a -second step. +Objects that inherit from FunctionVessel can be used (in tandem with PLMD::vesselbase::ActionWithVessel) +to store values and derivatives for a set of scalars or vectors that are calculated by a +PLMD::vesselbase::ActionWithVessel. Functions of these stored quantities can then be calculated in a +second step. */ class StoreDataVessel : public Vessel { -friend class Moments; + friend class Moments; private: /// Do the quantities being stored in here need derivatives bool hasderiv; -/// What is the maximum number of vectors we are going to -/// have to store when using lowmem option +/// What is the maximum number of vectors we are going to +/// have to store when using lowmem option unsigned max_lowmem_stash; -/// The size of the vector we are computing +/// The size of the vector we are computing unsigned vecsize; /// The amount of data per vector element unsigned nspace; -/// The currently active values +/// The currently active values // std::vector<unsigned> active_val; /// The active derivative elements std::vector<unsigned> active_der; /// The buffer - std::vector<double> local_buffer; + std::vector<double> local_buffer; /// The actions that are going to use the stored data - std::vector<ActionWithVessel*> userActions; -/// We create a vector of tempory MultiValues here so as to avoid + std::vector<ActionWithVessel*> userActions; +/// We create a vector of tempory MultiValues here so as to avoid /// lots of vector resizing - unsigned tmp_index; - std::vector<MultiValue> my_tmp_vals; + unsigned tmp_index; + std::vector<MultiValue> my_tmp_vals; protected: /// Is the weight differentiable bool weightHasDerivatives(); @@ -69,13 +69,13 @@ protected: bool usingLowMem(); /// Finish the setup of the storage object by setting how much /// data has to be stored - void completeSetup( const unsigned& , const unsigned& ); + void completeSetup( const unsigned&, const unsigned& ); /// Return value of nspace unsigned getNumberOfDerivativeSpacesPerComponent() const ; /// Retrieve the values from the underlying ActionWithVessel - void storeValues( const unsigned& , MultiValue& , std::vector<double>& ) const ; + void storeValues( const unsigned&, MultiValue&, std::vector<double>& ) const ; /// This stores the data we get from the calculation - void storeDerivatives( const unsigned& , MultiValue& myvals, std::vector<double>&, std::vector<unsigned>& ) const ; + void storeDerivatives( const unsigned&, MultiValue& myvals, std::vector<double>&, std::vector<unsigned>& ) const ; /// Get the ibuf'th local derivative value double getLocalDerivative( const unsigned& ibuf ); /// Set the ibuf'th local derivative value @@ -93,7 +93,7 @@ public: void recalculateStoredQuantity( const unsigned& myelm, MultiValue& myvals ); /// Set a hard cutoff on the weight of an element void setHardCutoffOnWeight( const double& mytol ); -/// Add an action that uses this data +/// Add an action that uses this data void addActionThatUses( ActionWithVessel* actionThatUses ); /// Return the number of components in the vector unsigned getNumberOfComponents() const { return vecsize; } @@ -106,7 +106,7 @@ public: /// Do all resizing of data virtual void resize(); /// - virtual std::string description(){ return ""; } + virtual std::string description() { return ""; } /// Get the number of derivatives for the ith value unsigned getNumberOfDerivatives( const unsigned& ); /// Get the size of the derivative list @@ -116,13 +116,13 @@ public: /// Final step in gathering data virtual void finish( const std::vector<double>& buffer ); /// Is a particular stored value active at the present time - bool storedValueIsActive( const unsigned& iatom ) const ; + bool storedValueIsActive( const unsigned& iatom ) const ; /// Set the active values void setActiveValsAndDerivatives( const std::vector<unsigned>& der_index ); /// Activate indexes (this is used at end of chain rule) - virtual void activateIndices( ActionWithVessel* ){} + virtual void activateIndices( ActionWithVessel* ) {} /// Forces on vectors should always be applied elsewhere - virtual bool applyForce(std::vector<double>&){ return false; } + virtual bool applyForce(std::vector<double>&) { return false; } /// Get the number of data users unsigned getNumberOfDataUsers() const ; /// Get one of the ith data user @@ -134,12 +134,12 @@ public: }; inline -bool StoreDataVessel::weightHasDerivatives(){ +bool StoreDataVessel::weightHasDerivatives() { return getAction()->weightHasDerivatives; } inline -bool StoreDataVessel::usingLowMem(){ +bool StoreDataVessel::usingLowMem() { return getAction()->lowmem; } @@ -153,7 +153,7 @@ bool StoreDataVessel::storedValueIsActive( const unsigned& iatom ) const { if( !getAction()->taskIsCurrentlyActive( iatom ) ) return false; unsigned jatom = getStoreIndex( iatom ); plumed_dbg_assert( jatom<getNumberOfStoredValues() ); - return local_buffer[jatom*vecsize*nspace]>epsilon; + return local_buffer[jatom*vecsize*nspace]>epsilon; } inline @@ -172,12 +172,12 @@ unsigned StoreDataVessel::getStoreIndex( const unsigned& ind ) const { // Binary search for required element - faster scaling than sequential search unsigned l=0, r=getAction()->nactive_tasks-1; - for(unsigned i=0;i<getAction()->nactive_tasks;++i){ - plumed_assert( l<=r ); - unsigned m = std::floor( (l + r)/2 ); - if( ind==getAction()->indexOfTaskInFullList[m] ) return m; - else if( getAction()->indexOfTaskInFullList[m]<ind ) l=m+1; - else if( getAction()->indexOfTaskInFullList[m]>ind ) r=m-1; + for(unsigned i=0; i<getAction()->nactive_tasks; ++i) { + plumed_assert( l<=r ); + unsigned m = std::floor( (l + r)/2 ); + if( ind==getAction()->indexOfTaskInFullList[m] ) return m; + else if( getAction()->indexOfTaskInFullList[m]<ind ) l=m+1; + else if( getAction()->indexOfTaskInFullList[m]>ind ) r=m-1; } plumed_merror("requested task is not active"); } @@ -188,7 +188,7 @@ unsigned StoreDataVessel::getTrueIndex( const unsigned& ind ) const { } inline -void StoreDataVessel::recalculateStoredQuantity( const unsigned& myelem, MultiValue& myvals ){ +void StoreDataVessel::recalculateStoredQuantity( const unsigned& myelem, MultiValue& myvals ) { getAction()->performTask( myelem, getAction()->getTaskCode(myelem), myvals ); } @@ -198,7 +198,7 @@ unsigned StoreDataVessel::getNumberOfDataUsers() const { } inline -ActionWithVessel* StoreDataVessel::getDataUser( const unsigned& idata ){ +ActionWithVessel* StoreDataVessel::getDataUser( const unsigned& idata ) { plumed_dbg_assert( idata<userActions.size() ); return userActions[idata]; } diff --git a/src/vesselbase/Sum.cpp b/src/vesselbase/Sum.cpp index 8bba669b2..4a1aedd5a 100644 --- a/src/vesselbase/Sum.cpp +++ b/src/vesselbase/Sum.cpp @@ -23,7 +23,7 @@ #include "VesselRegister.h" namespace PLMD { -namespace vesselbase{ +namespace vesselbase { class Sum : public FunctionVessel { public: @@ -36,22 +36,22 @@ public: PLUMED_REGISTER_VESSEL(Sum,"SUM") -void Sum::registerKeywords( Keywords& keys ){ +void Sum::registerKeywords( Keywords& keys ) { FunctionVessel::registerKeywords( keys ); } -void Sum::reserveKeyword( Keywords& keys ){ +void Sum::reserveKeyword( Keywords& keys ) { keys.reserve("vessel","SUM","calculate the sum of all the quantities."); keys.addOutputComponent("sum","SUM","the sum of values"); } Sum::Sum( const VesselOptions& da ) : -FunctionVessel(da) + FunctionVessel(da) { } -std::string Sum::value_descriptor(){ - return "the sum of all the values"; +std::string Sum::value_descriptor() { + return "the sum of all the values"; } double Sum::calcTransform( const double& val, double& dv ) const { diff --git a/src/vesselbase/ValueVessel.cpp b/src/vesselbase/ValueVessel.cpp index 8fb9ade21..a234ffe17 100644 --- a/src/vesselbase/ValueVessel.cpp +++ b/src/vesselbase/ValueVessel.cpp @@ -21,53 +21,53 @@ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ #include "ValueVessel.h" -namespace PLMD{ -namespace vesselbase{ +namespace PLMD { +namespace vesselbase { -void ValueVessel::registerKeywords( Keywords& keys ){ +void ValueVessel::registerKeywords( Keywords& keys ) { Vessel::registerKeywords( keys ); keys.add("compulsory","COMPONENT","1","The component we are using in the functions"); } ValueVessel::ValueVessel( const VesselOptions& da ): -Vessel(da), -no_output_value(false) + Vessel(da), + no_output_value(false) { parse("COMPONENT",mycomp); ActionWithValue* a=dynamic_cast<ActionWithValue*>( getAction() ); plumed_massert(a,"cannot create passable values as base action does not inherit from ActionWithValue"); int numval = getNumericalLabel(); - if( numval<0 && a->getNumberOfComponents()==0 ){ // This allows us to make multicolvars pretend to be colvars - this is used in AlphaRMSD etc - a->addValueWithDerivatives(); - a->setNotPeriodic(); - final_value=a->copyOutput( a->getNumberOfComponents()-1 ); - } else if( numval<0 ){ - no_output_value=true; final_value=new Value(); final_value->setNotPeriodic(); + if( numval<0 && a->getNumberOfComponents()==0 ) { // This allows us to make multicolvars pretend to be colvars - this is used in AlphaRMSD etc + a->addValueWithDerivatives(); + a->setNotPeriodic(); + final_value=a->copyOutput( a->getNumberOfComponents()-1 ); + } else if( numval<0 ) { + no_output_value=true; final_value=new Value(); final_value->setNotPeriodic(); } else { - plumed_massert( !a->exists(getAction()->getLabel() + "." + getLabel() ), "you can't create the name multiple times"); - a->addComponentWithDerivatives( getLabel() ); - a->componentIsNotPeriodic( getLabel() ); - final_value=a->copyOutput( a->getNumberOfComponents()-1 ); + plumed_massert( !a->exists(getAction()->getLabel() + "." + getLabel() ), "you can't create the name multiple times"); + a->addComponentWithDerivatives( getLabel() ); + a->componentIsNotPeriodic( getLabel() ); + final_value=a->copyOutput( a->getNumberOfComponents()-1 ); } } -ValueVessel::~ValueVessel(){ +ValueVessel::~ValueVessel() { if( no_output_value ) delete final_value; } -std::string ValueVessel::description(){ +std::string ValueVessel::description() { if( final_value->getName()==getAction()->getLabel() ) return "value " + getAction()->getLabel() + " contains " + value_descriptor(); return "value " + getAction()->getLabel() + "." + getLabel() + " contains " + value_descriptor(); } -bool ValueVessel::applyForce( std::vector<double>& forces ){ +bool ValueVessel::applyForce( std::vector<double>& forces ) { std::vector<double> tmpforce( forces.size() ); forces.assign(forces.size(),0.0); bool wasforced=false; - if( final_value->applyForce( tmpforce ) ){ - wasforced=true; - for(unsigned j=0;j<forces.size();++j) forces[j]+=tmpforce[j]; + if( final_value->applyForce( tmpforce ) ) { + wasforced=true; + for(unsigned j=0; j<forces.size(); ++j) forces[j]+=tmpforce[j]; } - return wasforced; + return wasforced; } } diff --git a/src/vesselbase/ValueVessel.h b/src/vesselbase/ValueVessel.h index 38d4d32f6..b80520419 100644 --- a/src/vesselbase/ValueVessel.h +++ b/src/vesselbase/ValueVessel.h @@ -30,10 +30,10 @@ #include "core/Value.h" namespace PLMD { -namespace vesselbase{ +namespace vesselbase { class ValueVessel : public Vessel { -private: +private: bool no_output_value; Value* final_value; protected: @@ -44,7 +44,7 @@ protected: public: static void registerKeywords( Keywords& keys ); explicit ValueVessel( const VesselOptions& da ); - ~ValueVessel(); + ~ValueVessel(); std::string description(); virtual std::string value_descriptor()=0; bool applyForce( std::vector<double>& forces ); @@ -63,7 +63,7 @@ double ValueVessel::getOutputValue() const { } inline -void ValueVessel::setOutputValue( const double& val ){ +void ValueVessel::setOutputValue( const double& val ) { final_value->set( val ); } diff --git a/src/vesselbase/Vessel.cpp b/src/vesselbase/Vessel.cpp index deec8b036..4ce9e10a0 100644 --- a/src/vesselbase/Vessel.cpp +++ b/src/vesselbase/Vessel.cpp @@ -26,66 +26,66 @@ #include "tools/Log.h" namespace PLMD { -namespace vesselbase{ +namespace vesselbase { Keywords VesselOptions::emptyKeys; VesselOptions::VesselOptions(const std::string& thisname, const std::string& thislab, const unsigned& nlab, const std::string& params, ActionWithVessel* aa ): -myname(thisname), -mylabel(thislab), -numlab(nlab), -action(aa), -keywords(emptyKeys), -parameters(params) + myname(thisname), + mylabel(thislab), + numlab(nlab), + action(aa), + keywords(emptyKeys), + parameters(params) { } VesselOptions::VesselOptions(const VesselOptions& da, const Keywords& keys ): -myname(da.myname), -mylabel(da.mylabel), -numlab(da.numlab), -action(da.action), -keywords(keys), -parameters(da.parameters) + myname(da.myname), + mylabel(da.mylabel), + numlab(da.numlab), + action(da.action), + keywords(keys), + parameters(da.parameters) { } -void Vessel::registerKeywords( Keywords& keys ){ +void Vessel::registerKeywords( Keywords& keys ) { plumed_assert( keys.size()==0 ); keys.add("optional","LABEL","the label used to reference this particular quantity"); } -std::string Vessel::transformName( const std::string& name ){ - std::string tlabel=name; - // Convert to lower case - std::transform( tlabel.begin(), tlabel.end(), tlabel.begin(), tolower ); - // Remove any underscore characters (as these are reserved) - for(unsigned i=0;;++i){ - std::size_t num=tlabel.find_first_of("_"); - if( num==std::string::npos ) break; - tlabel.erase( tlabel.begin() + num, tlabel.begin() + num + 1 ); - } - return tlabel; +std::string Vessel::transformName( const std::string& name ) { + std::string tlabel=name; + // Convert to lower case + std::transform( tlabel.begin(), tlabel.end(), tlabel.begin(), tolower ); + // Remove any underscore characters (as these are reserved) + for(unsigned i=0;; ++i) { + std::size_t num=tlabel.find_first_of("_"); + if( num==std::string::npos ) break; + tlabel.erase( tlabel.begin() + num, tlabel.begin() + num + 1 ); + } + return tlabel; } Vessel::Vessel( const VesselOptions& da ): -myname(da.myname), -numlab(da.numlab), -action(da.action), -line(Tools::getWords( da.parameters )), -keywords(da.keywords), -finished_read(false), -comm(da.action->comm), -log((da.action)->log) + myname(da.myname), + numlab(da.numlab), + action(da.action), + line(Tools::getWords( da.parameters )), + keywords(da.keywords), + finished_read(false), + comm(da.action->comm), + log((da.action)->log) { - if( da.mylabel.length()>0){ - mylabel=da.mylabel; + if( da.mylabel.length()>0) { + mylabel=da.mylabel; } else { - if( keywords.exists("LABEL") ) parse("LABEL",mylabel); - if( mylabel.length()==0 && numlab>=0 ){ - mylabel=transformName( myname ); std::string nn; - if(numlab>0){ Tools::convert( numlab, nn ); mylabel = mylabel + "-" + nn; } - } + if( keywords.exists("LABEL") ) parse("LABEL",mylabel); + if( mylabel.length()==0 && numlab>=0 ) { + mylabel=transformName( myname ); std::string nn; + if(numlab>0) { Tools::convert( numlab, nn ); mylabel = mylabel + "-" + nn; } + } } } @@ -97,37 +97,37 @@ std::string Vessel::getLabel() const { return mylabel; } -std::string Vessel::getAllInput(){ +std::string Vessel::getAllInput() { std::string fullstring; - for(unsigned i=0;i<line.size();++i){ - fullstring = fullstring + " " + line[i]; - } + for(unsigned i=0; i<line.size(); ++i) { + fullstring = fullstring + " " + line[i]; + } line.clear(); line.resize(0); return fullstring; } -void Vessel::parseFlag(const std::string&key, bool & t){ +void Vessel::parseFlag(const std::string&key, bool & t) { // Check keyword has been registered plumed_massert(keywords.exists(key), "keyword " + key + " has not been registered"); // Check keyword is a flag - if(!keywords.style(key,"nohtml")){ - plumed_massert(keywords.style(key,"flag"), "keyword " + key + " is not a flag"); + if(!keywords.style(key,"nohtml")) { + plumed_massert(keywords.style(key,"flag"), "keyword " + key + " is not a flag"); } // Read in the flag otherwise get the default value from the keywords object - if(!Tools::parseFlag(line,key,t)){ - if( keywords.style(key,"nohtml") ){ - t=false; - } else if ( !keywords.getLogicalDefault(key,t) ){ - plumed_merror("there is a flag with no logical default in a vessel - weird"); - } + if(!Tools::parseFlag(line,key,t)) { + if( keywords.style(key,"nohtml") ) { + t=false; + } else if ( !keywords.getLogicalDefault(key,t) ) { + plumed_merror("there is a flag with no logical default in a vessel - weird"); + } } } -void Vessel::checkRead(){ - if(!line.empty()){ +void Vessel::checkRead() { + if(!line.empty()) { std::string msg="cannot understand the following words from input : "; - for(unsigned i=0;i<line.size();i++) msg = msg + line[i] + ", "; + for(unsigned i=0; i<line.size(); i++) msg = msg + line[i] + ", "; error(msg); } finished_read=true; @@ -135,7 +135,7 @@ void Vessel::checkRead(){ if( describe.length()>0 ) log.printf(" %s\n", describe.c_str() ); } -void Vessel::error( const std::string& msg ){ +void Vessel::error( const std::string& msg ) { action->log.printf("ERROR for keyword %s in action %s with label %s : %s \n \n",myname.c_str(), (action->getName()).c_str(), (action->getLabel()).c_str(), msg.c_str() ); if(finished_read) keywords.print( log ); plumed_merror("ERROR for keyword " + myname + " in action " + action->getName() + " with label " + action->getLabel() + " : " + msg ); diff --git a/src/vesselbase/Vessel.h b/src/vesselbase/Vessel.h index f193e264c..ab96f3f41 100644 --- a/src/vesselbase/Vessel.h +++ b/src/vesselbase/Vessel.h @@ -30,26 +30,26 @@ #include "tools/Keywords.h" #include "ActionWithVessel.h" -namespace PLMD{ +namespace PLMD { class Communicator; class Log; -namespace vesselbase{ +namespace vesselbase { /** \ingroup TOOLBOX Vessels are an important component of class PLMD::ActionWithVessel. This class contains a large buffer array of doubles. The various elements of this array can be accessed through vessels which are used to structure the elements of the -double array. As the buffer array is just a vector of doubles it can be easily -mpi gathered or passed to another node. +double array. As the buffer array is just a vector of doubles it can be easily +mpi gathered or passed to another node. */ //class ActionWithVessel; class Vessel; -/// This class is used to pass the input to Vessels +/// This class is used to pass the input to Vessels class VesselOptions { friend class Vessel; private: @@ -67,13 +67,13 @@ private: public: /// The parameters that are read into the function std::string parameters; -/// The constructor +/// The constructor VesselOptions( const std::string& thisname, const std::string& thislab, const unsigned& nlab, const std::string& params, ActionWithVessel* aa ); VesselOptions(const VesselOptions& da, const Keywords& keys ); }; class Vessel { -friend class ActionWithVessel; + friend class ActionWithVessel; private: /// The keyword for the vessel in the input file std::string myname; @@ -100,7 +100,7 @@ protected: Communicator& comm; /// Return the numerical label int getNumericalLabel() const ; -/// Report an error +/// Report an error void error(const std::string& errmsg); /// Parse something from the input template<class T> @@ -111,7 +111,7 @@ protected: /// Parse one keyword as boolean flag void parseFlag(const std::string&key,bool&t); /// This returns the whole input line (it is used for less_than/more_than/between) - std::string getAllInput(); + std::string getAllInput(); /// Return a pointer to the action we are working in ActionWithVessel* getAction() const ; /// Return the value of the tolerance @@ -125,14 +125,14 @@ protected: public: /// Reference to the log on which to output details Log& log; -/// Reserve any keywords for this particular vessel +/// Reserve any keywords for this particular vessel static void registerKeywords( Keywords& keys ); /// Convert the name to the label of the component static std::string transformName( const std::string& name ); /// The constructor explicit Vessel( const VesselOptions& da ); /// Virtual destructor needed for proper inheritance - virtual ~Vessel(){} + virtual ~Vessel() {} /// Return the name std::string getName() const ; /// Return the label @@ -142,9 +142,9 @@ public: /// Return a description of the vessel contents virtual std::string description()=0; /// Set the start of the buffer - virtual void setBufferStart( unsigned& start ); + virtual void setBufferStart( unsigned& start ); /// Do something before the loop - virtual void prepare(){} + virtual void prepare() {} /// This is replaced in bridges so we can transform the derivatives virtual MultiValue& transformDerivatives( const unsigned& current, MultiValue& myvals, MultiValue& bvals ); /// Calculate the part of the vessel that is done in the loop @@ -158,22 +158,22 @@ public: }; template<class T> -void Vessel::parse(const std::string&key, T&t ){ +void Vessel::parse(const std::string&key, T&t ) { plumed_massert(keywords.exists(key),"keyword " + key + " has not been registered"); // Now try to read the keyword bool found=Tools::parse(line,key,t); std::string def; - if ( !found && keywords.style(key,"compulsory") ){ - if( keywords.getDefaultValue(key,def) ){ - plumed_massert( def.length()!=0 && Tools::convert(def,t), "default value is dubious"); - } else { - error("keyword " + key + " is comulsory for this vessel"); - } + if ( !found && keywords.style(key,"compulsory") ) { + if( keywords.getDefaultValue(key,def) ) { + plumed_massert( def.length()!=0 && Tools::convert(def,t), "default value is dubious"); + } else { + error("keyword " + key + " is comulsory for this vessel"); + } } } template<class T> -void Vessel::parseVector(const std::string&key,std::vector<T>&t){ +void Vessel::parseVector(const std::string&key,std::vector<T>&t) { // Check keyword has been registered plumed_massert(keywords.exists(key), "keyword " + key + " has not been registered"); unsigned size=t.size(); bool skipcheck=false; @@ -184,23 +184,23 @@ void Vessel::parseVector(const std::string&key,std::vector<T>&t){ found=Tools::parseVector(line,key,t); // Check vectors size is correct (not if this is atoms or ARG) - if( !keywords.style(key,"atoms") && found ){ - if( !skipcheck && t.size()!=size ) error("vector read in for keyword " + key + " has the wrong size"); + if( !keywords.style(key,"atoms") && found ) { + if( !skipcheck && t.size()!=size ) error("vector read in for keyword " + key + " has the wrong size"); } - // If it isn't read and it is compulsory see if a default value was specified - if ( !found && keywords.style(key,"compulsory") ){ - if( keywords.getDefaultValue(key,def) ){ - if( def.length()==0 || !Tools::convert(def,val) ){ - plumed_merror("weird default value for keyword " + key ); - } else { - for(unsigned i=0;i<t.size();++i) t[i]=val; - } - } else { - error("keyword " + key + " is compulsory"); - } - } else if ( !found ){ - t.resize(0); + // If it isn't read and it is compulsory see if a default value was specified + if ( !found && keywords.style(key,"compulsory") ) { + if( keywords.getDefaultValue(key,def) ) { + if( def.length()==0 || !Tools::convert(def,val) ) { + plumed_merror("weird default value for keyword " + key ); + } else { + for(unsigned i=0; i<t.size(); ++i) t[i]=val; + } + } else { + error("keyword " + key + " is compulsory"); + } + } else if ( !found ) { + t.resize(0); } } @@ -210,18 +210,18 @@ int Vessel::getNumericalLabel() const { } inline -void Vessel::setBufferStart( unsigned& start ){ +void Vessel::setBufferStart( unsigned& start ) { bufstart=start; start+=bufsize; } inline -MultiValue& Vessel::transformDerivatives( const unsigned& current, MultiValue& myvals, MultiValue& bvals ){ +MultiValue& Vessel::transformDerivatives( const unsigned& current, MultiValue& myvals, MultiValue& bvals ) { return myvals; } inline -void Vessel::resizeBuffer( const unsigned& n ){ - bufsize=n; +void Vessel::resizeBuffer( const unsigned& n ) { + bufsize=n; } inline diff --git a/src/vesselbase/VesselRegister.cpp b/src/vesselbase/VesselRegister.cpp index ea624a2f3..8e927ea03 100644 --- a/src/vesselbase/VesselRegister.cpp +++ b/src/vesselbase/VesselRegister.cpp @@ -23,31 +23,31 @@ #include "Vessel.h" #include <iostream> -namespace PLMD{ -namespace vesselbase{ +namespace PLMD { +namespace vesselbase { -VesselRegister::~VesselRegister(){ - if(m.size()>0){ +VesselRegister::~VesselRegister() { + if(m.size()>0) { std::string names=""; for(const auto & p : m) names+=p.first+" "; std::cerr<<"WARNING: Vessel "+ names +" has not been properly unregistered. This might lead to memory leak!!\n"; } } -VesselRegister& vesselRegister(){ +VesselRegister& vesselRegister() { static VesselRegister ans; return ans; } -void VesselRegister::remove(creator_pointer f){ - for(auto p=m.begin();p!=m.end();++p){ - if((*p).second==f){ +void VesselRegister::remove(creator_pointer f) { + for(auto p=m.begin(); p!=m.end(); ++p) { + if((*p).second==f) { m.erase(p); break; } } } -void VesselRegister::add(std::string keyword,creator_pointer f,keyword_pointer k,keyword_pointer ik){ +void VesselRegister::add(std::string keyword,creator_pointer f,keyword_pointer k,keyword_pointer ik) { plumed_massert(m.count(keyword)==0,"keyword has already been registered"); m.insert(std::pair<std::string,creator_pointer>(keyword,f)); k( keywords ); // Store the keywords for all the things @@ -57,24 +57,24 @@ void VesselRegister::add(std::string keyword,creator_pointer f,keyword_pointer k mk.insert(std::pair<std::string,keyword_pointer>(keyword,ik)); } -bool VesselRegister::check(std::string key){ +bool VesselRegister::check(std::string key) { if( m.count(key)>0 ) return true; return false; } -Vessel* VesselRegister::create(std::string keyword, const VesselOptions&da){ +Vessel* VesselRegister::create(std::string keyword, const VesselOptions&da) { Vessel* df; - if(check(keyword)){ - Keywords keys; mk[keyword](keys); - VesselOptions nda( da,keys ); - df=m[keyword](nda); - keys.destroyData(); + if(check(keyword)) { + Keywords keys; mk[keyword](keys); + VesselOptions nda( da,keys ); + df=m[keyword](nda); + keys.destroyData(); } else df=NULL; return df; } -Keywords VesselRegister::getKeywords(){ +Keywords VesselRegister::getKeywords() { return keywords; } diff --git a/src/vesselbase/VesselRegister.h b/src/vesselbase/VesselRegister.h index 4aea38e0b..a2bd24a20 100644 --- a/src/vesselbase/VesselRegister.h +++ b/src/vesselbase/VesselRegister.h @@ -29,13 +29,13 @@ #include "tools/Exception.h" #include "tools/Keywords.h" -namespace PLMD{ -namespace vesselbase{ +namespace PLMD { +namespace vesselbase { class Vessel; class VesselOptions; -class VesselRegister{ +class VesselRegister { private: /// Pointer to a function which, given the keyword for a distribution function, creates it typedef Vessel*(*creator_pointer)(const VesselOptions&); diff --git a/src/wrapper/Plumed.c b/src/wrapper/Plumed.c index 7aa2b20eb..75d9a9280 100644 --- a/src/wrapper/Plumed.c +++ b/src/wrapper/Plumed.c @@ -32,7 +32,7 @@ /* DECLARATION USED ONLY IN THIS FILE */ #ifdef __cplusplus - extern "C" { +extern "C" { #endif /** @@ -62,7 +62,7 @@ void plumed_dummy_finalize(void*); #endif #ifdef __cplusplus - } +} #endif /* END OF DECLARATION USED ONLY IN THIS FILE */ @@ -79,11 +79,11 @@ static int installed=0; static int dummy; -void*plumed_dummy_create(void){ +void*plumed_dummy_create(void) { return (void*)&dummy; } -void plumed_dummy_cmd(void*p,const char*key,const void*val){ +void plumed_dummy_cmd(void*p,const char*key,const void*val) { (void) p; /* avoid warning on unused parameter */ (void) key; /* avoid warning on unused parameter */ (void) val; /* avoid warning on unused parameter */ @@ -92,59 +92,59 @@ void plumed_dummy_cmd(void*p,const char*key,const void*val){ exit(1); } -void plumed_dummy_finalize(void*p){ +void plumed_dummy_finalize(void*p) { (void) p; /* avoid warning on unused parameter */ } #endif -plumed_plumedmain_function_holder* plumed_kernel_register(const plumed_plumedmain_function_holder* f){ +plumed_plumedmain_function_holder* plumed_kernel_register(const plumed_plumedmain_function_holder* f) { #ifdef __PLUMED_STATIC_KERNEL -/* - When __PLUMED_STATIC_KERNEL is defined, the function holder is initialized - to statically bound plumedmain_create,plumedmain_cmd,plumedmain_finalize and - cannot be changed. This saves from mis-set values for PLUMED_KERNEL -*/ - static plumed_plumedmain_function_holder g={plumedmain_create,plumedmain_cmd,plumedmain_finalize}; + /* + When __PLUMED_STATIC_KERNEL is defined, the function holder is initialized + to statically bound plumedmain_create,plumedmain_cmd,plumedmain_finalize and + cannot be changed. This saves from mis-set values for PLUMED_KERNEL + */ + static plumed_plumedmain_function_holder g= {plumedmain_create,plumedmain_cmd,plumedmain_finalize}; (void) f; /* avoid warning on unused parameter */ return &g; #else -/* - On the other hand, for runtime binding, we allow to reset the function holder on the - first call to plumed_kernel_register. - Notice that in principle plumed_kernel_register is entered *twice*: one for the first - plumed usage, and then from the PlumedMainInitializer object of the shared library. - This is why we set "first=0" only *after* loading the shared library. - Also notice that we should put some guard here for safe multithread calculations. -*/ - static plumed_plumedmain_function_holder g={plumed_dummy_create,plumed_dummy_cmd,plumed_dummy_finalize}; + /* + On the other hand, for runtime binding, we allow to reset the function holder on the + first call to plumed_kernel_register. + Notice that in principle plumed_kernel_register is entered *twice*: one for the first + plumed usage, and then from the PlumedMainInitializer object of the shared library. + This is why we set "first=0" only *after* loading the shared library. + Also notice that we should put some guard here for safe multithread calculations. + */ + static plumed_plumedmain_function_holder g= {plumed_dummy_create,plumed_dummy_cmd,plumed_dummy_finalize}; static int first=1; #ifdef __PLUMED_HAS_DLOPEN char* path; void* p; - if(first && f==NULL){ + if(first && f==NULL) { path=getenv("PLUMED_KERNEL"); #ifdef __PLUMED_DEFAULT_KERNEL -/* - This variable allows a default path for the kernel to be hardcoded. - Can be useful for hardcoding the predefined plumed location - still allowing the user to override this choice setting PLUMED_KERNEL. - The path should be chosen at compile time adding e.g. - -D__PLUMED_DEFAULT_KERNEL=/opt/local/lib/libplumed.dylib -*/ -/* This is required to add quotes */ + /* + This variable allows a default path for the kernel to be hardcoded. + Can be useful for hardcoding the predefined plumed location + still allowing the user to override this choice setting PLUMED_KERNEL. + The path should be chosen at compile time adding e.g. + -D__PLUMED_DEFAULT_KERNEL=/opt/local/lib/libplumed.dylib + */ + /* This is required to add quotes */ #define PLUMED_QUOTE_DIRECT(name) #name #define PLUMED_QUOTE(macro) PLUMED_QUOTE_DIRECT(macro) if(! (path && (*path) )) path=PLUMED_QUOTE(__PLUMED_DEFAULT_KERNEL); #endif - if(path && (*path)){ + if(path && (*path)) { fprintf(stderr,"+++ Loading the PLUMED kernel runtime +++\n"); fprintf(stderr,"+++ PLUMED_KERNEL=\"%s\" +++\n",path); p=dlopen(path,RTLD_NOW|RTLD_GLOBAL); - if(p){ + if(p) { fprintf(stderr,"+++ PLUMED kernel successfully loaded +++\n"); installed=1; - } else{ + } else { fprintf(stderr,"+++ PLUMED kernel not found ! +++\n"); fprintf(stderr,"+++ error message from dlopen(): %s\n",dlerror()); } @@ -159,7 +159,7 @@ plumed_plumedmain_function_holder* plumed_kernel_register(const plumed_plumedmai /* C wrappers: */ -plumed plumed_create(void){ +plumed plumed_create(void) { plumed p; plumed_plumedmain_function_holder*h=plumed_kernel_register(NULL); assert(h); @@ -169,7 +169,7 @@ plumed plumed_create(void){ return p; } -void plumed_cmd(plumed p,const char*key,const void*val){ +void plumed_cmd(plumed p,const char*key,const void*val) { plumed_plumedmain_function_holder*h=plumed_kernel_register(NULL); assert(p.p); assert(h); @@ -177,7 +177,7 @@ void plumed_cmd(plumed p,const char*key,const void*val){ (*(h->cmd))(p.p,key,val); } -void plumed_finalize(plumed p){ +void plumed_finalize(plumed p) { plumed_plumedmain_function_holder*h=plumed_kernel_register(NULL); assert(p.p); assert(h); @@ -186,63 +186,63 @@ void plumed_finalize(plumed p){ p.p=NULL; } -int plumed_installed(void){ +int plumed_installed(void) { plumed_kernel_register(NULL); return installed; } /* we declare a Plumed_g_main object here, in such a way that it is always available */ -static plumed gmain={NULL}; +static plumed gmain= {NULL}; -plumed plumed_global(void){ +plumed plumed_global(void) { return gmain; } -void plumed_gcreate(void){ +void plumed_gcreate(void) { assert(gmain.p==NULL); gmain=plumed_create(); } -void plumed_gcmd(const char*key,const void*val){ +void plumed_gcmd(const char*key,const void*val) { assert(gmain.p); plumed_cmd(gmain,key,val); } -void plumed_gfinalize(void){ +void plumed_gfinalize(void) { assert(gmain.p); plumed_finalize(gmain); gmain.p=NULL; } -int plumed_ginitialized(void){ +int plumed_ginitialized(void) { if(gmain.p) return 1; else return 0; } -void plumed_c2f(plumed p,char*c){ +void plumed_c2f(plumed p,char*c) { unsigned i; unsigned char* cc; -/* - Convert the address stored in p.p into a proper FORTRAN string - made of only ASCII characters. For this to work, the two following - assertions should be satisfied: -*/ + /* + Convert the address stored in p.p into a proper FORTRAN string + made of only ASCII characters. For this to work, the two following + assertions should be satisfied: + */ assert(CHAR_BIT<=12); assert(sizeof(p.p)<=16); assert(c); cc=(unsigned char*)&p.p; - for(i=0;i<sizeof(p.p);i++){ -/* - characters will range between '0' (ASCII 48) and 'o' (ASCII 111=48+63) -*/ + for(i=0; i<sizeof(p.p); i++) { + /* + characters will range between '0' (ASCII 48) and 'o' (ASCII 111=48+63) + */ c[2*i]=cc[i]/64+48; c[2*i+1]=cc[i]%64+48; } } -plumed plumed_f2c(const char*c){ +plumed plumed_f2c(const char*c) { plumed p; unsigned i; unsigned char* cc; @@ -252,10 +252,10 @@ plumed plumed_f2c(const char*c){ assert(c); cc=(unsigned char*)&p.p; - for(i=0;i<sizeof(p.p);i++){ -/* - perform the reversed transform -*/ + for(i=0; i<sizeof(p.p); i++) { + /* + perform the reversed transform + */ cc[i]=(c[2*i]-48)*64 + (c[2*i+1]-48); } return p; @@ -263,12 +263,12 @@ plumed plumed_f2c(const char*c){ #ifdef __cplusplus - extern "C" { +extern "C" { #endif /* Fortran wrappers - These are just like the global C wrappers. They are + These are just like the global C wrappers. They are just defined here and not declared in the .h file since they should not be used from c/c++ anyway. */ @@ -277,47 +277,47 @@ plumed plumed_f2c(const char*c){ First we assume no name mangling */ -void plumed_f_installed(int*i){ +void plumed_f_installed(int*i) { assert(i); *i=plumed_installed(); } -void plumed_f_ginitialized(int*i){ +void plumed_f_ginitialized(int*i) { assert(i); *i=plumed_ginitialized(); } -void plumed_f_gcreate(void){ +void plumed_f_gcreate(void) { plumed_gcreate(); } -void plumed_f_gcmd(char*key,void*val){ +void plumed_f_gcmd(char*key,void*val) { plumed_gcmd(key,val); } -void plumed_f_gfinalize(void){ +void plumed_f_gfinalize(void) { plumed_gfinalize(); } -void plumed_f_create(char*c){ +void plumed_f_create(char*c) { plumed p; p=plumed_create(); plumed_c2f(p,c); } -void plumed_f_cmd(char*c,char*key,void*val){ +void plumed_f_cmd(char*c,char*key,void*val) { plumed p; p=plumed_f2c(c); plumed_cmd(p,key,val); -} +} -void plumed_f_finalize(char*c){ +void plumed_f_finalize(char*c) { plumed p; p=plumed_f2c(c); plumed_finalize(p); } -void plumed_f_global(char*c){ +void plumed_f_global(char*c) { plumed_c2f(gmain,c); } @@ -335,15 +335,15 @@ void plumed_f_global(char*c){ void upper ##_ implem \ void upper ##__ implem -IMPLEMENT(plumed_f_gcreate, PLUMED_F_GCREATE, (void){plumed_f_gcreate();}) -IMPLEMENT(plumed_f_gcmd, PLUMED_F_GCMD, (char* key,void* val){plumed_f_gcmd(key,val);}) -IMPLEMENT(plumed_f_gfinalize, PLUMED_F_GFINALIZE, (void){plumed_f_gfinalize();}) -IMPLEMENT(plumed_f_ginitialized,PLUMED_F_GINITIALIZED,(int*i){plumed_f_ginitialized(i);}) -IMPLEMENT(plumed_f_create, PLUMED_F_CREATE, (char*c){plumed_f_create(c);}) -IMPLEMENT(plumed_f_cmd, PLUMED_F_CMD, (char*c,char* key,void* val){plumed_f_cmd(c,key,val);}) -IMPLEMENT(plumed_f_finalize, PLUMED_F_FINALIZE, (char*c){plumed_f_finalize(c);}) -IMPLEMENT(plumed_f_installed, PLUMED_F_INSTALLED, (int*i){plumed_f_installed(i);}) -IMPLEMENT(plumed_f_global, PLUMED_F_GLOBAL, (char*c){plumed_f_global(c);}) +IMPLEMENT(plumed_f_gcreate, PLUMED_F_GCREATE, (void) {plumed_f_gcreate();}) +IMPLEMENT(plumed_f_gcmd, PLUMED_F_GCMD, (char* key,void* val) {plumed_f_gcmd(key,val);}) +IMPLEMENT(plumed_f_gfinalize, PLUMED_F_GFINALIZE, (void) {plumed_f_gfinalize();}) +IMPLEMENT(plumed_f_ginitialized,PLUMED_F_GINITIALIZED,(int*i) {plumed_f_ginitialized(i);}) +IMPLEMENT(plumed_f_create, PLUMED_F_CREATE, (char*c) {plumed_f_create(c);}) +IMPLEMENT(plumed_f_cmd, PLUMED_F_CMD, (char*c,char* key,void* val) {plumed_f_cmd(c,key,val);}) +IMPLEMENT(plumed_f_finalize, PLUMED_F_FINALIZE, (char*c) {plumed_f_finalize(c);}) +IMPLEMENT(plumed_f_installed, PLUMED_F_INSTALLED, (int*i) {plumed_f_installed(i);}) +IMPLEMENT(plumed_f_global, PLUMED_F_GLOBAL, (char*c) {plumed_f_global(c);}) #ifdef __cplusplus } diff --git a/src/wrapper/Plumed.h b/src/wrapper/Plumed.h index 537cc1209..2db9a21f4 100644 --- a/src/wrapper/Plumed.h +++ b/src/wrapper/Plumed.h @@ -112,7 +112,7 @@ To check if plumed library is available (this is useful for runtime linking), use \verbatim - (C) plumed_installed + (C) plumed_installed (C++) PLMD::Plumed::installed (FORTRAN) PLUMED_F_INSTALLED \endverbatim @@ -168,7 +168,7 @@ */ #ifdef __cplusplus - extern "C" { +extern "C" { #endif /* Generic function pointer */ @@ -201,10 +201,10 @@ typedef struct { not to change across plumed versions. See \ref ReferencePlumedH. */ typedef struct { -/** - \private - \brief Void pointer holding the real PlumedMain structure -*/ + /** + \private + \brief Void pointer holding the real PlumedMain structure + */ void*p; } plumed; @@ -328,7 +328,7 @@ void c_routine(char handler[32]){ plumed plumed_f2c(const char* c); #ifdef __cplusplus - } +} #endif #ifdef __cplusplus @@ -345,149 +345,149 @@ namespace PLMD { This class provides a C++ interface to PLUMED. */ -class Plumed{ -/** - C structure. -*/ +class Plumed { + /** + C structure. + */ plumed main; -/** - keeps track if the object was created from scratch using - the defaults destructor (reference=false) or if it was imported - from C or FORTRAN (reference=true). In the latter case, the - plumed_finalize() method is not called when destructing the object, - since it is expected to be finalized in the C/FORTRAN code -*/ + /** + keeps track if the object was created from scratch using + the defaults destructor (reference=false) or if it was imported + from C or FORTRAN (reference=true). In the latter case, the + plumed_finalize() method is not called when destructing the object, + since it is expected to be finalized in the C/FORTRAN code + */ bool reference; public: -/** - Check if plumed is installed (for runtime binding) - \return true if plumed is installed, false otherwise - \note Equivalent to plumed_installed() but returns a bool -*/ + /** + Check if plumed is installed (for runtime binding) + \return true if plumed is installed, false otherwise + \note Equivalent to plumed_installed() but returns a bool + */ static bool installed(); -/** - Check if global-plumed has been initialized - \return true if global plumed object (see global()) is initialized (i.e. if gcreate() has been - called), false otherwise. - \note Equivalent to plumed_ginitialized() but returns a bool -*/ + /** + Check if global-plumed has been initialized + \return true if global plumed object (see global()) is initialized (i.e. if gcreate() has been + called), false otherwise. + \note Equivalent to plumed_ginitialized() but returns a bool + */ static bool ginitialized(); -/** - Initialize global-plumed. - \note Equivalent to plumed_gcreate() -*/ + /** + Initialize global-plumed. + \note Equivalent to plumed_gcreate() + */ static void gcreate(); -/** - Send a command to global-plumed - \param key The name of the command to be executed - \param val The argument. It is declared as const to allow calls like gcmd("A","B"), - but for some choice of key it can change the content - \note Equivalent to plumed_gcmd() -*/ + /** + Send a command to global-plumed + \param key The name of the command to be executed + \param val The argument. It is declared as const to allow calls like gcmd("A","B"), + but for some choice of key it can change the content + \note Equivalent to plumed_gcmd() + */ static void gcmd(const char* key,const void* val); -/** - Finalize global-plumed -*/ + /** + Finalize global-plumed + */ static void gfinalize(); -/** - Returns the Plumed global object - \return The Plumed global object -*/ + /** + Returns the Plumed global object + \return The Plumed global object + */ static Plumed global(); -/** - Constructor. - \note Performs the same task a plumed_create() -*/ + /** + Constructor. + \note Performs the same task a plumed_create() + */ Plumed(); -/** - Clone a Plumed object from a FORTRAN char* handler - \param c The FORTRAN handler (a char[32]). - - \attention The Plumed object created in this manner - will not finalize the corresponding plumed structure. - It is expected that the FORTRAN code calls plumed_c_finalize for it -*/ + /** + Clone a Plumed object from a FORTRAN char* handler + \param c The FORTRAN handler (a char[32]). + + \attention The Plumed object created in this manner + will not finalize the corresponding plumed structure. + It is expected that the FORTRAN code calls plumed_c_finalize for it + */ // to have maximum portability of this file I do not use the explicit keyword here // I thus add a suppress command for cppcheck // cppcheck-suppress noExplicitConstructor Plumed(const char*c); -/** - Clone a Plumed object from a C plumed structure - \param p The C plumed structure. - - \attention The Plumed object created in this manner - will not finalize the corresponding plumed structure. - It is expected that the C code calls plumed_finalize for it -*/ + /** + Clone a Plumed object from a C plumed structure + \param p The C plumed structure. + + \attention The Plumed object created in this manner + will not finalize the corresponding plumed structure. + It is expected that the C code calls plumed_finalize for it + */ // to have maximum portability of this file I do not use the explicit keyword here // I thus add a suppress command for cppcheck // cppcheck-suppress noExplicitConstructor Plumed(plumed p); private: -/** Copy constructor is disabled (private and unimplemented) - The problem here is that after copying it will not be clear who is - going to finalize the corresponding plumed structure. -*/ + /** Copy constructor is disabled (private and unimplemented) + The problem here is that after copying it will not be clear who is + going to finalize the corresponding plumed structure. + */ Plumed(const Plumed&); -/** Assignment operator is disabled (private and unimplemented) - The problem here is that after copying it will not be clear who is - going to finalize the corresponding plumed structure. -*/ + /** Assignment operator is disabled (private and unimplemented) + The problem here is that after copying it will not be clear who is + going to finalize the corresponding plumed structure. + */ Plumed&operator=(const Plumed&); public: -/* - PLUMED 2.4 requires a C++11 compiler. - Anyway, since Plumed.h file might be redistributed with other codes - and it should be possible to combine it with earlier PLUMED versions, - we here explicitly check if C+11 is available before enabling move semantics. - This could still create problems if a compiler 'cheats', setting __cplusplus > 199711L - but not supporting move semantics. Hopefully will not happen! -*/ + /* + PLUMED 2.4 requires a C++11 compiler. + Anyway, since Plumed.h file might be redistributed with other codes + and it should be possible to combine it with earlier PLUMED versions, + we here explicitly check if C+11 is available before enabling move semantics. + This could still create problems if a compiler 'cheats', setting __cplusplus > 199711L + but not supporting move semantics. Hopefully will not happen! + */ #if __cplusplus > 199711L -/** Move constructor. - Only if move semantics is enabled. - It allows storing PLMD::Plumed objects in STL containers. -*/ + /** Move constructor. + Only if move semantics is enabled. + It allows storing PLMD::Plumed objects in STL containers. + */ Plumed(Plumed&&); -/** Move assignment. - Only if move semantics is enabled. -*/ + /** Move assignment. + Only if move semantics is enabled. + */ Plumed& operator=(Plumed&&); #endif -/** - Retrieve the C plumed structure for this object -*/ + /** + Retrieve the C plumed structure for this object + */ operator plumed()const; -/** - Retrieve a FORTRAN handler for this object - \param c The FORTRAN handler (a char[32]). -*/ + /** + Retrieve a FORTRAN handler for this object + \param c The FORTRAN handler (a char[32]). + */ void toFortran(char*c)const; -/** - Send a command to this plumed object - \param key The name of the command to be executed - \param val The argument. It is declared as const to allow calls like p.cmd("A","B"), - but for some choice of key it can change the content - \note Equivalent to plumed_cmd() -*/ + /** + Send a command to this plumed object + \param key The name of the command to be executed + \param val The argument. It is declared as const to allow calls like p.cmd("A","B"), + but for some choice of key it can change the content + \note Equivalent to plumed_cmd() + */ void cmd(const char*key,const void*val=NULL); -/** - Destructor - - Destructor is virtual so as to allow correct inheritance from Plumed object. - To avoid linking problems with g++, I specify "inline" also here (in principle - it should be enough to specify it down in the definition of the function, but - for some reason that I do not understand g++ does not inline it properly in that - case and complains when Plumed.h is included but Plumed.o is not linked. Anyway, the - way it is done here seems to work properly). -*/ + /** + Destructor + + Destructor is virtual so as to allow correct inheritance from Plumed object. + To avoid linking problems with g++, I specify "inline" also here (in principle + it should be enough to specify it down in the definition of the function, but + for some reason that I do not understand g++ does not inline it properly in that + case and complains when Plumed.h is included but Plumed.o is not linked. Anyway, the + way it is done here seems to work properly). + */ inline virtual ~Plumed(); }; /* All methods are inlined so as to avoid the compilation of an extra c++ file */ inline -bool Plumed::installed(){ +bool Plumed::installed() { return plumed_installed(); } @@ -517,7 +517,7 @@ Plumed::Plumed(Plumed&& p): {} inline -Plumed& Plumed::operator=(Plumed&& p){ +Plumed& Plumed::operator=(Plumed&& p) { main=p.main; reference=p.reference; return *this; @@ -525,47 +525,47 @@ Plumed& Plumed::operator=(Plumed&& p){ #endif inline -Plumed::operator plumed()const{ +Plumed::operator plumed()const { return main; } inline -void Plumed::toFortran(char*c)const{ +void Plumed::toFortran(char*c)const { plumed_c2f(main,c); } inline -void Plumed::cmd(const char*key,const void*val){ +void Plumed::cmd(const char*key,const void*val) { plumed_cmd(main,key,val); } inline -Plumed::~Plumed(){ +Plumed::~Plumed() { if(!reference)plumed_finalize(main); } inline -bool Plumed::ginitialized(){ +bool Plumed::ginitialized() { return plumed_ginitialized(); } inline -void Plumed::gcreate(){ +void Plumed::gcreate() { plumed_gcreate(); } inline -void Plumed::gcmd(const char* key,const void* val){ +void Plumed::gcmd(const char* key,const void* val) { plumed_gcmd(key,val); } inline -void Plumed::gfinalize(){ +void Plumed::gfinalize() { plumed_gfinalize(); } inline -Plumed Plumed::global(){ +Plumed Plumed::global() { return plumed_global(); } -- GitLab