LCOV - code coverage report
Current view: top level - function - Combine.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 42 45 93.3 %
Date: 2025-04-08 21:11:17 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2011-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 "Combine.h"
      23             : #include "FunctionTemplateBase.h"
      24             : #include "FunctionShortcut.h"
      25             : #include "FunctionOfScalar.h"
      26             : #include "FunctionOfVector.h"
      27             : #include "FunctionOfMatrix.h"
      28             : #include "core/ActionRegister.h"
      29             : 
      30             : namespace PLMD {
      31             : namespace function {
      32             : 
      33             : //+PLUMEDOC FUNCTION COMBINE
      34             : /*
      35             : Calculate a polynomial combination of a set of other variables.
      36             : 
      37             : This action takes in $N_{arg}$ arguments ($x_i$) and computes the following function of them:
      38             : 
      39             : \f[
      40             : C=\sum_{i=1}^{N_{arg}} c_i (x_i-a_i)^{p_i}
      41             : \f]
      42             : 
      43             : The $c_i$, $a_i$ and $p_i$ values in this expression are provided through the COEFFICIENTS, PARAMETERS and POWERS keywords respectively.
      44             : The following example illustrates how this action can be used to calculate and print the square of the distance between atom 1 and atom 2.
      45             : 
      46             : ```plumed
      47             : d: DISTANCE ATOMS=1,2 COMPONENTS
      48             : c: COMBINE ARG=d.x,d.y,d.z COEFFICIENTS=1,1,1 PARAMETERS=0,0,0 POWERS=2,2,2 PERIODIC=NO
      49             : PRINT ARG=c FILE=colvar
      50             : ```
      51             : 
      52             : Notice that if the COEFFICIENTS keyword is absent all the $c_i$ values are set equal to 1.
      53             : Furthermore, if the PARAMETERS keyword is absent all the $a_i$ values are set equal to 0.
      54             : We can thus make use of these defaults and rewrite the input above as:
      55             : 
      56             : ```plumed
      57             : d: DISTANCE ATOMS=1,2 COMPONENTS
      58             : c: COMBINE ARG=d.x,d.y,d.z POWERS=2,2,2 PERIODIC=NO
      59             : PRINT ARG=c FILE=colvar
      60             : ```
      61             : 
      62             : Notice that we cannot remove the POWERS keyword here as if it is absent all the $p_i$ values are set equal to 1.
      63             : 
      64             : ## Periodic arguments
      65             : 
      66             : The COMBINE action is not able to predict the periodic domain for the function that is computed from the arguments
      67             : automatically.  The user is thus forced to specify it explicitly. Use PERIODIC=NO if the resulting variable is not periodic,
      68             : and PERIODIC=A,B where A and B are the two boundaries for the periodic domain if the resulting variable is periodic.
      69             : The following provides an example where the output from combine has a periodic domain.  In this input we are taking the
      70             : cube of a dihedral angle.  The dihedral angle has a periodic domain that runs from $-\pi$ to $\pi$.  The cube of this variable
      71             : thus has a periodic domain that runs from $-\pi^3$ to $\pi^3$ as indicated in the following input.
      72             : 
      73             : ```plumed
      74             : t: TORSION ATOMS=1,3,5,7
      75             : #c: COMBINE ARG=t POWERS=3 PERIODIC=-31.0062766802998,31.0062766802998
      76             : c: COMBINE ARG=t POWERS=3 PERIODIC=-pi^3,pi^3
      77             : PRINT ARG=c FILE=colvar
      78             : ```
      79             : 
      80             : ## Vector arguments
      81             : 
      82             : The two examples in the previous section demonstrate how to use the COMBINE action with scalar arguments.  However, you can also
      83             : pass arguments to this action that have a rank greater than zero.  For example, in the example below COMBINE accepts three
      84             : vectors with 4 elements in input:
      85             : 
      86             : ```plumed
      87             : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4 ATOMS3=5,6 ATOMS4=7,8 COMPONENTS
      88             : c: COMBINE ARG=d.x,d.y,d.z POWERS=2,2,2 PERIODIC=NO
      89             : PRINT ARG=c FILE=colvar
      90             : ```
      91             : 
      92             : The output from the COMBINE action here is also a vector with four elements. The first element of this vector is the square of the
      93             : distance betwen atoms 1 and 2, the secton is the square of the distance between atoms 3 and 4 and so on.
      94             : 
      95             : The COMBINE action can also take a mixture of scalars and vectors in input.  The following input illustrates an
      96             : COMBINE action that takes vectors and scalars in input.
      97             : 
      98             : ```plumed
      99             : p: CONSTANT VALUE=2
     100             : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4 ATOMS3=5,6 ATOMS4=7,8
     101             : c: COMBINE ARG=d,p COEFFICIENTS=4,-1 POWERS=2.5,1 PERIODIC=NO
     102             : PRINT ARG=c FILE=colvar
     103             : ```
     104             : 
     105             : The elements of the vector that is calculated by the COMBINE action here are given by:
     106             : 
     107             : $$
     108             : c_i = 4d_i^{2.5} - 2
     109             : $$
     110             : 
     111             : The $d_i$ in this expression are the distances that were calculated by the DISTANCE action. The 2 comes
     112             : from the scalar `p` that passed to the ARG action in input.  As a single scalar is passed the same number is
     113             : used when calculating all 4 elements of the output vector.  In other words, the scalar behaves as if it is a
     114             : vector with four components that all have the same value.
     115             : 
     116             : Lastly, notice that if you pass a single vector in input to COMBINE as in the following example, the output is still a vector:
     117             : 
     118             : ```plumed
     119             : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4 ATOMS3=5,6 ATOMS4=7,8
     120             : c: COMBINE ARG=d COEFFICIENTS=4 POWERS=2.5 PARAMETERS=0.5 PERIODIC=NO
     121             : PRINT ARG=c FILE=colvar
     122             : ```
     123             : 
     124             : To calculate the 4-dimensional output by the COMBINE action here we subtract 0.5 from each of the input distances, raise
     125             : the result from this subtraction to the power 2.5 and then multiply the result by 4.
     126             : 
     127             : If you want to calculate a linear combination of the elements of a vector using the formula at the top of the page you should use
     128             : the [CUSTOM](CUSTOM.md) action to transform all the components of the input vector.  You can then add all the results from these
     129             : transformations together using [SUM](SUM.md).
     130             : 
     131             : ## Matrix arguments
     132             : 
     133             : You can also use matrices in the input to the COMBINE action as illustrated below:
     134             : 
     135             : ```plumed
     136             : d: DISTANCE_MATRIX GROUPA=1,2 GROUPB=3,4,5 COMPONENTS
     137             : c: COMBINE ARG=d.x,d.y,d.z POWERS=2,2,2 PERIODIC=NO
     138             : PRINT ARG=c FILE=colvar
     139             : ```
     140             : 
     141             : The input to the combine action here consists of three $2\times3$ matrices. The output is thus a $2\times3$ matrix that contains the squares of the
     142             : distances between the atoms in GROUPA and the atoms in GROUPB.  Notice that all the input matrices must have the same size as the elements of the final
     143             : matrix are calculated by applying the formula in the first section of this input to each set of elements to the input matrices in turn.
     144             : 
     145             : The input to this action can be a combination of matrices and scalars.  If your input arguments are an $N\times M$ matrix and a scalar the scalar is treated as if
     146             : it is a $N\times M$ matrix which has all its elements equal to the input scalar. You __cannot__ use a mixture of vectors and matrices in the input to this action.
     147             : 
     148             : Furthermore, if you pass a single matrix to COMBINE the output is a matrix.  To calculate a linear combination of all the elements in a matrix using the formula at the top of the page you should use
     149             : the [CUSTOM](CUSTOM.md) action to transform all the components of the input vector.  You can then add all the results from these transformations together using [SUM](SUM.md).
     150             : 
     151             : */
     152             : //+ENDPLUMEDOC
     153             : 
     154             : //+PLUMEDOC FUNCTION COMBINE_SCALAR
     155             : /*
     156             : Calculate a polynomial combination of a set of other variables.
     157             : 
     158             : \par Examples
     159             : 
     160             : */
     161             : //+ENDPLUMEDOC
     162             : 
     163             : //+PLUMEDOC FUNCTION COMBINE_VECTOR
     164             : /*
     165             : Add together the elements of a set of vectors elementwise
     166             : 
     167             : \par Examples
     168             : 
     169             : */
     170             : //+ENDPLUMEDOC
     171             : 
     172             : //+PLUMEDOC COLVAR COMBINE_MATRIX
     173             : /*
     174             : Calculate the sum of a number of matrices
     175             : 
     176             : \par Examples
     177             : 
     178             : */
     179             : //+ENDPLUMEDOC
     180             : 
     181             : typedef FunctionShortcut<Combine> CombineShortcut;
     182             : PLUMED_REGISTER_ACTION(CombineShortcut,"COMBINE")
     183             : typedef FunctionOfScalar<Combine> ScalarCombine;
     184             : PLUMED_REGISTER_ACTION(ScalarCombine,"COMBINE_SCALAR")
     185             : typedef FunctionOfVector<Combine> VectorCombine;
     186             : PLUMED_REGISTER_ACTION(VectorCombine,"COMBINE_VECTOR")
     187             : typedef FunctionOfMatrix<Combine> MatrixCombine;
     188             : PLUMED_REGISTER_ACTION(MatrixCombine,"COMBINE_MATRIX")
     189             : 
     190        1072 : void Combine::registerKeywords(Keywords& keys) {
     191        1072 :   keys.use("PERIODIC");
     192        1072 :   keys.add("compulsory","COEFFICIENTS","1.0","the coefficients of the arguments in your function");
     193        1072 :   keys.add("compulsory","PARAMETERS","0.0","the parameters of the arguments in your function");
     194        1072 :   keys.add("compulsory","POWERS","1.0","the powers to which you are raising each of the arguments in your function");
     195        1072 :   keys.addFlag("NORMALIZE",false,"normalize all the coefficients so that in total they are equal to one");
     196        2144 :   keys.setValueDescription("scalar/vector/matrix","a linear compbination");
     197        1072 : }
     198             : 
     199         306 : void Combine::read( ActionWithArguments* action ) {
     200         306 :   coefficients.resize( action->getNumberOfArguments() );
     201         306 :   parameters.resize( action->getNumberOfArguments() );
     202         306 :   powers.resize( action->getNumberOfArguments() );
     203         611 :   parseVector(action,"COEFFICIENTS",coefficients);
     204         305 :   if(coefficients.size()!=static_cast<unsigned>(action->getNumberOfArguments())) {
     205           0 :     action->error("Size of COEFFICIENTS array should be the same as number for arguments");
     206             :   }
     207         609 :   parseVector(action,"PARAMETERS",parameters);
     208         304 :   if(parameters.size()!=static_cast<unsigned>(action->getNumberOfArguments())) {
     209           0 :     action->error("Size of PARAMETERS array should be the same as number for arguments");
     210             :   }
     211         607 :   parseVector(action,"POWERS",powers);
     212         303 :   if(powers.size()!=static_cast<unsigned>(action->getNumberOfArguments())) {
     213           0 :     action->error("Size of POWERS array should be the same as number for arguments");
     214             :   }
     215             : 
     216         303 :   parseFlag(action,"NORMALIZE",normalize);
     217         303 :   if(normalize) {
     218             :     double n=0.0;
     219          43 :     for(unsigned i=0; i<coefficients.size(); i++) {
     220          38 :       n+=coefficients[i];
     221             :     }
     222          43 :     for(unsigned i=0; i<coefficients.size(); i++) {
     223          38 :       coefficients[i]*=(1.0/n);
     224             :     }
     225             :   }
     226             : 
     227         303 :   action->log.printf("  with coefficients:");
     228        1506 :   for(unsigned i=0; i<coefficients.size(); i++) {
     229        1203 :     action->log.printf(" %f",coefficients[i]);
     230             :   }
     231         303 :   action->log.printf("\n  with parameters:");
     232        1506 :   for(unsigned i=0; i<parameters.size(); i++) {
     233        1203 :     action->log.printf(" %f",parameters[i]);
     234             :   }
     235         303 :   action->log.printf("\n  and powers:");
     236        1506 :   for(unsigned i=0; i<powers.size(); i++) {
     237        1203 :     action->log.printf(" %f",powers[i]);
     238             :   }
     239         303 :   action->log.printf("\n");
     240         303 : }
     241             : 
     242     4369200 : void Combine::calc( const ActionWithArguments* action, const std::vector<double>& args, std::vector<double>& vals, Matrix<double>& derivatives ) const {
     243     4369200 :   vals[0]=0.0;
     244    10983391 :   for(unsigned i=0; i<coefficients.size(); ++i) {
     245     6614191 :     double cv = action->difference( i, parameters[i], args[i] );
     246     6614191 :     vals[0] += coefficients[i]*pow( cv, powers[i] );
     247     6614191 :     derivatives(0,i) = coefficients[i]*powers[i]*pow(cv,powers[i]-1.0);
     248             :   }
     249     4369200 : }
     250             : 
     251             : }
     252             : }
     253             : 
     254             : 

Generated by: LCOV version 1.16