LCOV - code coverage report
Current view: top level - function - Moments.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 46 68 67.6 %
Date: 2026-03-30 11:13:23 Functions: 5 7 71.4 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2011-2017 The plumed team
       3             :    (see the PEOPLE file at the root of the distribution for a list of names)
       4             : 
       5             :    See http://www.plumed.org for more information.
       6             : 
       7             :    This file is part of plumed, version 2.
       8             : 
       9             :    plumed is free software: you can redistribute it and/or modify
      10             :    it under the terms of the GNU Lesser General Public License as published by
      11             :    the Free Software Foundation, either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    plumed is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU Lesser General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU Lesser General Public License
      20             :    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
      21             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      22             : #include "FunctionShortcut.h"
      23             : #include "FunctionOfScalar.h"
      24             : #include "FunctionOfVector.h"
      25             : #include "core/ActionRegister.h"
      26             : #include "FunctionTemplateBase.h"
      27             : 
      28             : #include <cmath>
      29             : 
      30             : namespace PLMD {
      31             : namespace function {
      32             : 
      33             : //+PLUMEDOC FUNCTION MOMENTS
      34             : /*
      35             : Calculate the moments of the distribution of input quantities
      36             : 
      37             : \par Examples
      38             : 
      39             : */
      40             : //+ENDPLUMEDOC
      41             : 
      42             : //+PLUMEDOC FUNCTION MOMENTS_SCALAR
      43             : /*
      44             : Calculate the moments of the distribution of input quantities
      45             : 
      46             : \par Examples
      47             : 
      48             : */
      49             : //+ENDPLUMEDOC
      50             : 
      51             : //+PLUMEDOC FUNCTION MOMENTS_VECTOR
      52             : /*
      53             : Calculate the moments of the distribution of input vectors
      54             : 
      55             : \par Examples
      56             : 
      57             : */
      58             : //+ENDPLUMEDOC
      59             : 
      60          66 : class Moments : public FunctionTemplateBase {
      61             :   bool isperiodic, scalar_out;
      62             :   double min, max, pfactor;
      63             :   std::vector<int> powers;
      64             : public:
      65             :   void registerKeywords(Keywords& keys) override;
      66             :   void read( ActionWithArguments* action ) override;
      67           0 :   bool zeroRank() const override {
      68           7 :     return scalar_out;
      69             :   }
      70           0 :   bool doWithTasks() const override {
      71         221 :     return !scalar_out;
      72             :   }
      73             :   std::vector<std::string> getComponentsPerLabel() const override ;
      74             :   void setPeriodicityForOutputs( ActionWithValue* action ) override;
      75             :   void calc( const ActionWithArguments* action, const std::vector<double>& args, std::vector<double>& vals, Matrix<double>& derivatives ) const override;
      76             : };
      77             : 
      78             : typedef FunctionShortcut<Moments> MomentsShortcut;
      79             : PLUMED_REGISTER_ACTION(MomentsShortcut,"MOMENTS")
      80             : typedef FunctionOfScalar<Moments> ScalarMoments;
      81             : PLUMED_REGISTER_ACTION(ScalarMoments,"MOMENTS_SCALAR")
      82             : typedef FunctionOfVector<Moments> VectorMoments;
      83             : PLUMED_REGISTER_ACTION(VectorMoments,"MOMENTS_VECTOR")
      84             : 
      85          33 : void Moments::registerKeywords(Keywords& keys) {
      86          66 :   keys.add("compulsory","POWERS","calculate the central moments of the distribution of collective variables. "
      87             :            "The \\f$m\\f$th central 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 "
      88             :            "the average for the distribution. The POWERS keyword takes a lists of integers as input or a range. Each integer is a value of \\f$m\\f$. The final "
      89             :            "calculated values can be referenced using moment-\\f$m\\f$.");
      90          66 :   keys.addOutputComponent("moment","default","the central moments of the distribution of values. The second central moment "
      91             :                           "would be referenced elsewhere in the input file using "
      92             :                           "<em>label</em>.moment-2, the third as <em>label</em>.moment-3, etc.");
      93          33 : }
      94             : 
      95           5 : void Moments::read( ActionWithArguments* action ) {
      96           5 :   scalar_out = action->getNumberOfArguments()==1;
      97           5 :   if( scalar_out && action->getPntrToArgument(0)->getRank()==0 ) {
      98           0 :     action->error("cannot calculate moments if only given one variable");
      99             :   }
     100             : 
     101           5 :   isperiodic = (action->getPntrToArgument(0))->isPeriodic();
     102           5 :   if( isperiodic ) {
     103             :     std::string str_min, str_max;
     104           0 :     (action->getPntrToArgument(0))->getDomain( str_min, str_max );
     105           0 :     for(unsigned i=1; i<action->getNumberOfArguments(); ++i) {
     106           0 :       if( !(action->getPntrToArgument(i))->isPeriodic() ) {
     107           0 :         action->error("cannot mix periodic and non periodic variables when calculating moments");
     108             :       }
     109             :       std::string str_min2, str_max2;
     110           0 :       (action->getPntrToArgument(i))->getDomain( str_min2, str_max2);
     111           0 :       if( str_min!=str_min2 || str_max!=str_max2 ) {
     112           0 :         action->error("all input arguments should have same domain when calculating moments");
     113             :       }
     114             :     }
     115           0 :     Tools::convert(str_min,min);
     116           0 :     Tools::convert(str_max,max);
     117           0 :     pfactor = 2*pi / ( max-min );
     118             :   } else {
     119          14 :     for(unsigned i=1; i<action->getNumberOfArguments(); ++i) {
     120           9 :       if( (action->getPntrToArgument(i))->isPeriodic() ) {
     121           0 :         action->error("cannot mix periodic and non periodic variables when calculating moments");
     122             :       }
     123             :     }
     124             :   }
     125             : 
     126           5 :   parseVector(action,"POWERS",powers);
     127          13 :   for(unsigned i=0; i<powers.size(); ++i) {
     128           8 :     if( powers[i]<2 ) {
     129           0 :       action->error("first central moment is zero do you really need to calculate that");
     130             :     }
     131           8 :     action->log.printf("  computing %dth central moment of distribution of input cvs \n", powers[i]);
     132             :   }
     133           5 : }
     134             : 
     135           5 : std::vector<std::string> Moments::getComponentsPerLabel() const {
     136             :   std::vector<std::string> comp;
     137             :   std::string num;
     138          13 :   for(unsigned i=0; i<powers.size(); ++i) {
     139           8 :     Tools::convert(powers[i],num);
     140          16 :     comp.push_back( "-" + num );
     141             :   }
     142           5 :   return comp;
     143           0 : }
     144             : 
     145           5 : void Moments::setPeriodicityForOutputs( ActionWithValue* action ) {
     146          13 :   for(unsigned i=0; i<powers.size(); ++i) {
     147             :     std::string num;
     148           8 :     Tools::convert(powers[i],num);
     149          16 :     action->componentIsNotPeriodic("moment-" + num);
     150             :   }
     151           5 : }
     152             : 
     153         222 : void Moments::calc( const ActionWithArguments* action, const std::vector<double>& args, std::vector<double>& vals, Matrix<double>& derivatives ) const {
     154             :   double mean=0;
     155         222 :   double inorm = 1.0 / static_cast<double>( args.size() );
     156         222 :   if( isperiodic ) {
     157             :     double sinsum=0, cossum=0, val;
     158           0 :     for(unsigned i=0; i<args.size(); ++i) {
     159           0 :       val=pfactor*( args[i] - min );
     160           0 :       sinsum+=sin(val);
     161           0 :       cossum+=cos(val);
     162             :     }
     163           0 :     mean = 0.5 + atan2( inorm*sinsum, inorm*cossum ) / (2*pi);
     164           0 :     mean = min + (max-min)*mean;
     165             :   } else {
     166        1758 :     for(unsigned i=0; i<args.size(); ++i) {
     167        1536 :       mean+=args[i];
     168             :     }
     169         222 :     mean *= inorm;
     170             :   }
     171             : 
     172             :   Value* arg0 = action->getPntrToArgument(0);
     173         656 :   for(unsigned npow=0; npow<powers.size(); ++npow) {
     174             :     double dev1=0;
     175        3406 :     for(unsigned i=0; i<args.size(); ++i) {
     176        2972 :       dev1+=pow( arg0->difference( mean, args[i] ), powers[npow] - 1 );
     177             :     }
     178         434 :     dev1*=inorm;
     179         434 :     vals[npow] = 0;
     180         434 :     double prefactor = powers[npow]*inorm;
     181        3406 :     for(unsigned i=0; i<args.size(); ++i) {
     182        2972 :       double tmp=arg0->difference( mean, args[i] );
     183        2972 :       vals[npow] += inorm*pow( tmp, powers[npow] );
     184        2972 :       derivatives(npow,i) = prefactor*(pow( tmp, powers[npow] - 1 ) - dev1);
     185             :     }
     186             :   }
     187         222 : }
     188             : 
     189             : }
     190             : }
     191             : 
     192             : 

Generated by: LCOV version 1.16