LCOV - code coverage report
Current view: top level - function - Stats.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 103 112 92.0 %
Date: 2026-03-30 11:13:23 Functions: 3 4 75.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2015-2023 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 "Function.h"
      23             : #include "core/ActionRegister.h"
      24             : 
      25             : namespace PLMD {
      26             : namespace function {
      27             : 
      28             : //+PLUMEDOC FUNCTION STATS
      29             : /*
      30             : Calculates statistical properties of a set of collective variables with respect to a set of reference values.
      31             : 
      32             : In particular it calculates and stores as components the sum of the squared deviations, the correlation, the
      33             : slope and the intercept of a linear fit.
      34             : 
      35             : The reference values can be either provided as values using PARAMETERS or using value without derivatives
      36             : from other actions using PARARG (for example using experimental values from collective variables such as
      37             : \ref CS2BACKBONE, \ref RDC, \ref NOE, \ref PRE).
      38             : 
      39             : \par Examples
      40             : 
      41             : The following input tells plumed to print the distance between three couple of atoms
      42             : and compare them with three reference distances.
      43             : 
      44             : \plumedfile
      45             : d1: DISTANCE ATOMS=10,50
      46             : d2: DISTANCE ATOMS=1,100
      47             : d3: DISTANCE ATOMS=45,75
      48             : st: STATS ARG=d1,d2,d3 PARAMETERS=1.5,4.0,2.0
      49             : PRINT ARG=d1,d2,d3,st.*
      50             : \endplumedfile
      51             : 
      52             : */
      53             : //+ENDPLUMEDOC
      54             : 
      55             : 
      56             : class Stats :
      57             :   public Function {
      58             :   std::vector<double> parameters;
      59             :   bool sqdonly;
      60             :   bool components;
      61             :   bool upperd;
      62             : public:
      63             :   explicit Stats(const ActionOptions&);
      64             :   void calculate() override;
      65             :   static void registerKeywords(Keywords& keys);
      66             : };
      67             : 
      68             : 
      69             : PLUMED_REGISTER_ACTION(Stats,"STATS")
      70             : 
      71          35 : void Stats::registerKeywords(Keywords& keys) {
      72          35 :   Function::registerKeywords(keys);
      73          35 :   keys.use("ARG");
      74          70 :   keys.add("optional","PARARG","the input for this action is the scalar output from one or more other actions without derivatives.");
      75          70 :   keys.add("optional","PARAMETERS","the parameters of the arguments in your function");
      76          70 :   keys.addFlag("SQDEVSUM",false,"calculates only SQDEVSUM");
      77          70 :   keys.addFlag("SQDEV",false,"calculates and store the SQDEV as components");
      78          70 :   keys.addFlag("UPPERDISTS",false,"calculates and store the SQDEV as components");
      79          70 :   keys.addOutputComponent("sqdevsum","default","the sum of the squared deviations between arguments and parameters");
      80          70 :   keys.addOutputComponent("corr","default","the correlation between arguments and parameters");
      81          70 :   keys.addOutputComponent("slope","default","the slope of a linear fit between arguments and parameters");
      82          70 :   keys.addOutputComponent("intercept","default","the intercept of a linear fit between arguments and parameters");
      83          70 :   keys.addOutputComponent("sqd","SQDEV","the squared deviations between arguments and parameters");
      84          35 : }
      85             : 
      86          31 : Stats::Stats(const ActionOptions&ao):
      87             :   Action(ao),
      88             :   Function(ao),
      89          31 :   sqdonly(false),
      90          31 :   components(false),
      91          31 :   upperd(false) {
      92          62 :   parseVector("PARAMETERS",parameters);
      93          31 :   if(parameters.size()!=static_cast<unsigned>(getNumberOfArguments())&&!parameters.empty()) {
      94           0 :     error("Size of PARAMETERS array should be either 0 or the same as of the number of arguments in ARG1");
      95             :   }
      96             : 
      97             :   std::vector<Value*> arg2;
      98          62 :   parseArgumentList("PARARG",arg2);
      99             : 
     100          31 :   if(!arg2.empty()) {
     101          14 :     if(parameters.size()>0) {
     102           0 :       error("It is not possible to use PARARG and PARAMETERS together");
     103             :     }
     104          14 :     if(arg2.size()!=getNumberOfArguments()) {
     105           0 :       error("Size of PARARG array should be the same as number for arguments in ARG");
     106             :     }
     107        5912 :     for(unsigned i=0; i<arg2.size(); i++) {
     108        5898 :       parameters.push_back(arg2[i]->get());
     109        5898 :       if(arg2[i]->hasDerivatives()==true) {
     110           0 :         error("PARARG can only accept arguments without derivatives");
     111             :       }
     112             :     }
     113             :   }
     114             : 
     115          31 :   if(parameters.size()!=getNumberOfArguments()) {
     116           0 :     error("PARARG or PARAMETERS arrays should include the same number of elements as the arguments in ARG");
     117             :   }
     118             : 
     119          31 :   if(getNumberOfArguments()<2) {
     120           0 :     error("STATS need at least two arguments to be used");
     121             :   }
     122             : 
     123          31 :   parseFlag("SQDEVSUM",sqdonly);
     124          31 :   parseFlag("SQDEV",components);
     125          31 :   parseFlag("UPPERDISTS",upperd);
     126             : 
     127          31 :   if(sqdonly&&components) {
     128           0 :     error("You cannot used SQDEVSUM and SQDEV at the sametime");
     129             :   }
     130             : 
     131          31 :   if(components) {
     132          12 :     sqdonly = true;
     133             :   }
     134             : 
     135          31 :   if(!arg2.empty()) {
     136          14 :     log.printf("  using %zu parameters from inactive actions:", arg2.size());
     137             :   } else {
     138          17 :     log.printf("  using %zu parameters:", arg2.size());
     139             :   }
     140        6000 :   for(unsigned i=0; i<parameters.size(); i++) {
     141        5969 :     log.printf(" %f",parameters[i]);
     142             :   }
     143          31 :   log.printf("\n");
     144             : 
     145          31 :   if(sqdonly) {
     146          17 :     if(components) {
     147          60 :       for(unsigned i=0; i<parameters.size(); i++) {
     148             :         std::string num;
     149          48 :         Tools::convert(i,num);
     150          48 :         addComponentWithDerivatives("sqd-"+num);
     151          96 :         componentIsNotPeriodic("sqd-"+num);
     152             :       }
     153             :     } else {
     154           5 :       addComponentWithDerivatives("sqdevsum");
     155          10 :       componentIsNotPeriodic("sqdevsum");
     156             :     }
     157             :   } else {
     158          14 :     addComponentWithDerivatives("sqdevsum");
     159          14 :     componentIsNotPeriodic("sqdevsum");
     160          14 :     addComponentWithDerivatives("corr");
     161          14 :     componentIsNotPeriodic("corr");
     162          14 :     addComponentWithDerivatives("slope");
     163          14 :     componentIsNotPeriodic("slope");
     164          14 :     addComponentWithDerivatives("intercept");
     165          28 :     componentIsNotPeriodic("intercept");
     166             :   }
     167             : 
     168          31 :   checkRead();
     169          31 : }
     170             : 
     171         122 : void Stats::calculate() {
     172         122 :   if(sqdonly) {
     173             : 
     174             :     double nsqd = 0.;
     175             :     Value* val;
     176          53 :     if(!components) {
     177         106 :       val=getPntrToComponent("sqdevsum");
     178             :     }
     179         174 :     for(unsigned i=0; i<parameters.size(); ++i) {
     180         121 :       double dev = getArgument(i)-parameters[i];
     181         121 :       if(upperd&&dev<0) {
     182             :         dev=0.;
     183             :       }
     184         121 :       if(components) {
     185           0 :         val=getPntrToComponent(i);
     186           0 :         val->set(dev*dev);
     187             :       } else {
     188         121 :         nsqd += dev*dev;
     189             :       }
     190         121 :       setDerivative(val,i,2.*dev);
     191             :     }
     192          53 :     if(!components) {
     193             :       val->set(nsqd);
     194             :     }
     195             : 
     196             :   } else {
     197             : 
     198             :     double scx=0., scx2=0., scy=0., scy2=0., scxy=0.;
     199             : 
     200        6230 :     for(unsigned i=0; i<parameters.size(); ++i) {
     201        6161 :       const double tmpx=getArgument(i);
     202        6161 :       const double tmpy=parameters[i];
     203        6161 :       scx  += tmpx;
     204        6161 :       scx2 += tmpx*tmpx;
     205        6161 :       scy  += tmpy;
     206        6161 :       scy2 += tmpy*tmpy;
     207        6161 :       scxy += tmpx*tmpy;
     208             :     }
     209             : 
     210          69 :     const double ns = parameters.size();
     211             : 
     212          69 :     const double num = ns*scxy - scx*scy;
     213          69 :     const double idev2x = 1./(ns*scx2-scx*scx);
     214          69 :     const double idevx = std::sqrt(idev2x);
     215          69 :     const double idevy = 1./std::sqrt(ns*scy2-scy*scy);
     216             : 
     217             :     /* sd */
     218          69 :     const double nsqd = scx2 + scy2 - 2.*scxy;
     219             :     /* correlation */
     220          69 :     const double correlation = num * idevx * idevy;
     221             :     /* slope and intercept */
     222          69 :     const double slope = num * idev2x;
     223          69 :     const double inter = (scy - slope * scx)/ns;
     224             : 
     225          69 :     Value* valuea=getPntrToComponent("sqdevsum");
     226          69 :     Value* valueb=getPntrToComponent("corr");
     227          69 :     Value* valuec=getPntrToComponent("slope");
     228         138 :     Value* valued=getPntrToComponent("intercept");
     229             : 
     230             :     valuea->set(nsqd);
     231             :     valueb->set(correlation);
     232             :     valuec->set(slope);
     233             :     valued->set(inter);
     234             : 
     235             :     /* derivatives */
     236        6230 :     for(unsigned i=0; i<parameters.size(); ++i) {
     237        6161 :       const double common_d1 = (ns*parameters[i]-scy)*idevx;
     238        6161 :       const double common_d2 = num*(ns*getArgument(i)-scx)*idev2x*idevx;
     239        6161 :       const double common_d3 = common_d1 - common_d2;
     240             : 
     241             :       /* sqdevsum */
     242        6161 :       const double sq_der = 2.*(getArgument(i)-parameters[i]);
     243             :       /* correlation */
     244        6161 :       const double co_der = common_d3*idevy;
     245             :       /* slope */
     246        6161 :       const double sl_der = (common_d1-2.*common_d2)*idevx;
     247             :       /* intercept */
     248        6161 :       const double int_der = -(slope+ scx*sl_der)/ns;
     249             : 
     250             :       setDerivative(valuea,i,sq_der);
     251        6161 :       setDerivative(valueb,i,co_der);
     252        6161 :       setDerivative(valuec,i,sl_der);
     253        6161 :       setDerivative(valued,i,int_der);
     254             :     }
     255             : 
     256             :   }
     257         122 : }
     258             : 
     259             : }
     260             : }
     261             : 
     262             : 

Generated by: LCOV version 1.16