LCOV - code coverage report
Current view: top level - vesselbase - Moments.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 85 95 89.5 %
Date: 2021-11-18 15:22:58 Functions: 15 15 100.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2013-2020 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 "VesselRegister.h"
      23             : #include "Vessel.h"
      24             : #include "StoreDataVessel.h"
      25             : #include "ActionWithVessel.h"
      26             : 
      27             : namespace PLMD {
      28             : namespace vesselbase {
      29             : 
      30             : // This is not the most efficient implementation
      31             : // The calculation of all the colvars is parallelized
      32             : // but the loops for calculating moments are not
      33             : // Feel free to reimplement this if you know how
      34          24 : class Moments : public Vessel {
      35             : private:
      36             :   unsigned mycomponent;
      37             :   StoreDataVessel* mystash;
      38             :   std::vector<unsigned> powers;
      39             :   std::vector<Value*> value_out;
      40             : public:
      41             :   static void registerKeywords( Keywords& keys );
      42             :   static void reserveKeyword( Keywords& keys );
      43             :   explicit Moments( const vesselbase::VesselOptions& da );
      44             :   std::string description();
      45             :   void resize();
      46        6936 :   void calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const {}
      47             :   void finish( const std::vector<double>& buffer );
      48             :   bool applyForce( std::vector<double>& forces );
      49             : };
      50             : 
      51        7372 : PLUMED_REGISTER_VESSEL(Moments,"MOMENTS")
      52             : 
      53           8 : void Moments::registerKeywords( Keywords& keys ) {
      54           8 :   Vessel::registerKeywords( keys );
      55          16 :   keys.remove("LABEL");
      56          40 :   keys.add("compulsory","COMPONENT","1","the component of the vector for which to calculate this quantity");
      57          32 :   keys.add("compulsory","MOMENTS","the list of moments that you would like to calculate");
      58           8 : }
      59             : 
      60        1839 : void Moments::reserveKeyword( Keywords& keys ) {
      61        7356 :   keys.reserve("optional","MOMENTS","calculate the moments of the distribution of collective variables. "
      62             :                "The mth 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 "
      63             :                "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 "
      64             :                "calculated values can be referenced using moment-\\f$m\\f$.  You can use the COMPONENT keyword in this action but the syntax is slightly different. "
      65             :                "If you would like the second and third moments of the third component you would use MOMENTS={COMPONENT=3 MOMENTS=2-3}.  The moments would then be referred to "
      66             :                "using the labels moment-3-2 and moment-3-3.  This syntax is also required if you are using numbered MOMENT keywords i.e. MOMENTS1, MOMENTS2...");
      67        5517 :   keys.reset_style("MOMENTS","vessel");
      68        7356 :   keys.addOutputComponent("moment","MOMENTS","the central moments of the distribution of values. The second moment "
      69             :                           "would be referenced elsewhere in the input file using "
      70             :                           "<em>label</em>.moment-2, the third as <em>label</em>.moment-3, etc.");
      71        1839 : }
      72             : 
      73           8 : Moments::Moments( const vesselbase::VesselOptions& da) :
      74          16 :   Vessel(da)
      75             : {
      76           8 :   mystash = getAction()->buildDataStashes( NULL );
      77           8 :   ActionWithValue* a=dynamic_cast<ActionWithValue*>( getAction() );
      78           8 :   plumed_massert(a,"cannot create passable values as base action does not inherit from ActionWithValue");
      79             : 
      80           8 :   std::vector<std::string> moments; std::string valstr;
      81           8 :   if( getNumericalLabel()==0 ) {
      82             :     valstr = "moment-";
      83          18 :     moments=Tools::getWords(getAllInput(),"\t\n ,");
      84           6 :     Tools::interpretRanges(moments); mycomponent=1;
      85             :   } else {
      86           4 :     std::string numstr; parse("COMPONENT",mycomponent);
      87           6 :     Tools::convert( mycomponent, numstr); valstr = "moment-"  + numstr + "-";
      88           4 :     parseVector("MOMENTS",moments); Tools::interpretRanges(moments);
      89             :   }
      90             :   unsigned nn;
      91          52 :   for(unsigned i=0; i<moments.size(); ++i) {
      92          24 :     a->addComponentWithDerivatives( valstr + moments[i] );
      93          24 :     a->componentIsNotPeriodic( valstr + moments[i] );
      94          24 :     value_out.push_back( a->copyOutput( a->getNumberOfComponents()-1 ) );
      95          12 :     Tools::convert( moments[i], nn );
      96          12 :     if( nn<2 ) error("moments are only possible for m>=2" );
      97          24 :     powers.push_back( nn ); std::string num; Tools::convert(powers[i],num);
      98             :   }
      99           8 : }
     100             : 
     101          28 : void Moments::resize() {
     102             :   resizeBuffer(0);
     103          28 :   if( getAction()->derivativesAreRequired() ) {
     104         220 :     for(unsigned i=0; i<value_out.size(); ++i) value_out[i]->resizeDerivatives( getAction()->getNumberOfDerivatives() );
     105             :   }
     106          28 : }
     107             : 
     108           8 : std::string Moments::description() {
     109             :   std::string descri, num;
     110           8 :   Tools::convert(powers[0],num);
     111           8 :   if( getNumericalLabel()==0 ) {
     112          54 :     descri = "value " + getAction()->getLabel() + "." + "moment-" + num + " contains the " + num + "th moment of the distribution";
     113          18 :     for(unsigned i=1; i<powers.size(); ++i) {
     114           2 :       Tools::convert(powers[i],num);
     115          20 :       descri = descri + "\n  value " + getAction()->getLabel() + "." + "moment-" + num + " contains the " + num + "th moment of the distribution";
     116             :     }
     117             :   } else {
     118           2 :     std::string numlab; Tools::convert( mycomponent, numlab );
     119          24 :     descri = "value " + getAction()->getLabel() + "." + "moment-" + numlab + "-" + num + " contains the " + num + "th moment for the distribution of component " + numlab;
     120          10 :     for(unsigned i=1; i<powers.size(); ++i) {
     121           2 :       Tools::convert(powers[i],num);
     122          26 :       descri = descri + "\n  value " + getAction()->getLabel() + "." + "moment-" + numlab + "-" + num + " contains the " + num + "th moment for the distribution of component " + numlab;
     123             :     }
     124             :   }
     125           8 :   return descri;
     126             : }
     127             : 
     128         822 : void Moments::finish( const std::vector<double>& buffer ) {
     129             :   const double pi=3.141592653589793238462643383279502884197169399375105820974944592307;
     130             :   unsigned nvals=getAction()->getFullNumberOfTasks();
     131         822 :   std::vector<double>  myvalues( getAction()->getNumberOfQuantities() );
     132             : 
     133        1644 :   double mean=0; Value myvalue;
     134         822 :   if( getAction()->isPeriodic() ) {
     135           0 :     std::string str_min, str_max; getAction()->retrieveDomain( str_min, str_max );
     136           0 :     double pfactor, min, max; Tools::convert(str_min,min); Tools::convert(str_max,max);
     137           0 :     pfactor = 2*pi / ( max-min ); myvalue.setDomain( str_min, str_max );
     138             :     double sinsum=0, cossum=0, val;
     139           0 :     for(unsigned i=0; i<mystash->getNumberOfStoredValues(); ++i) {
     140           0 :       mystash->retrieveSequentialValue( i, false, myvalues );
     141           0 :       val=pfactor*( myvalues[mycomponent] - min );
     142           0 :       sinsum+=sin(val); cossum+=cos(val);
     143             :     }
     144           0 :     mean = 0.5 + atan2( sinsum / static_cast<double>( nvals ), cossum / static_cast<double>( nvals ) ) / (2*pi);
     145           0 :     mean = min + (max-min)*mean;
     146             :   } else {
     147        7758 :     for(unsigned i=0; i<mystash->getNumberOfStoredValues(); ++i) {
     148       13872 :       mystash->retrieveSequentialValue( i, false, myvalues ); mean+=myvalues[mycomponent];
     149             :     }
     150         822 :     mean/=static_cast<double>( nvals ); myvalue.setNotPeriodic();
     151             :   }
     152             : 
     153        5346 :   for(unsigned npow=0; npow<powers.size(); ++npow) {
     154             :     double dev1=0;
     155        1234 :     if( value_out[0]->getNumberOfDerivatives()>0 ) {
     156        4606 :       for(unsigned i=0; i<mystash->getNumberOfStoredValues(); ++i) {
     157        4172 :         mystash->retrieveSequentialValue( i, false, myvalues );
     158        8344 :         dev1+=pow( myvalue.difference( mean, myvalues[mycomponent] ), powers[npow] - 1 );
     159             :       }
     160         434 :       dev1/=static_cast<double>( nvals );
     161             :     }
     162             : 
     163             :     double moment=0;
     164        3702 :     MultiValue myvals( getAction()->getNumberOfQuantities(), getAction()->getNumberOfDerivatives() ); myvals.clearAll();
     165       11006 :     for(unsigned i=0; i<mystash->getNumberOfStoredValues(); ++i) {
     166        9772 :       mystash->retrieveSequentialValue( i, false, myvalues );
     167       19544 :       double tmp=myvalue.difference( mean, myvalues[mycomponent] );
     168        9772 :       moment+=pow( tmp, powers[npow] );
     169        9772 :       if( value_out[npow]->getNumberOfDerivatives() ) {
     170        4172 :         double pref=pow( tmp, powers[npow] - 1 ) - dev1;
     171        4172 :         mystash->retrieveDerivatives( i, false, myvals );
     172      329588 :         for(unsigned j=0; j<myvals.getNumberActive(); ++j) {
     173             :           unsigned jatom=myvals.getActiveIndex(j);
     174      325416 :           value_out[npow]->addDerivative(jatom, pref*myvals.getDerivative( mycomponent, jatom ) );
     175             :         }
     176        4172 :         myvals.clearAll();
     177             :       }
     178             :     }
     179        2102 :     if( value_out[npow]->getNumberOfDerivatives()>0 ) value_out[npow]->chainRule( powers[npow] / static_cast<double>( nvals ) );
     180        1234 :     value_out[npow]->set( moment / static_cast<double>( nvals ) );
     181             :   }
     182         822 : }
     183             : 
     184         432 : bool Moments::applyForce( std::vector<double>& forces ) {
     185         432 :   std::vector<double> tmpforce( forces.size() );
     186         864 :   forces.assign(forces.size(),0.0); bool wasforced=false;
     187        3396 :   for(unsigned i=0; i<value_out.size(); ++i) {
     188         844 :     if( value_out[i]->applyForce( tmpforce ) ) {
     189             :       wasforced=true;
     190           0 :       for(unsigned j=0; j<forces.size(); ++j) forces[j]+=tmpforce[j];
     191             :     }
     192             :   }
     193         432 :   return wasforced;
     194             : }
     195             : 
     196             : }
     197        5517 : }

Generated by: LCOV version 1.14