LCOV - code coverage report
Current view: top level - generic - Constant.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 96 106 90.6 %
Date: 2026-11-05 10:19:04 Functions: 3 7 42.9 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2011-2018 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 "core/ActionWithValue.h"
      23             : #include "core/ActionRegister.h"
      24             : #include "tools/IFile.h"
      25             : 
      26             : //+PLUMEDOC COLVAR CONSTANT
      27             : /*
      28             : Create a constant value that can be passed to actions
      29             : 
      30             : This action can be used to create constant scalars, vectors or matrices.  These
      31             : constants are assigned to a value, which can then be used later in the input.  For example,
      32             : the following input creates a value `c` and sets it equal to the constant value 4.5.
      33             : 
      34             : ```plumed
      35             : c: CONSTANT VALUE=4.5
      36             : PRINT ARG=c STRIDE=1 FILE=constant_scalar
      37             : ```
      38             : 
      39             : The output file printed by this input will contain a column in which every element is 4.5
      40             : 
      41             : By contrast, this input creates a five element vector called `v` with elements equal to
      42             : 1, 2, 3, 4 and 5:
      43             : 
      44             : ```plumed
      45             : v: CONSTANT VALUES=1,2,3,4,5
      46             : PRINT ARG=v FILE=constant_vector
      47             : ```
      48             : 
      49             : The PRINT action will now output a file with 6 columns.  The first of these columns will be the time.
      50             : Every element of the second column will be 1, every element of the second column will be 2 and so on.
      51             : 
      52             : Notice that can generate 5 scalar constant rather than a vector using an input like this:
      53             : 
      54             : ```plumed
      55             : c: CONSTANT VALUES=1,2,3,4,5 SCALARS
      56             : PRINT ARG=c.v-0,c.v-1,c.v-2,c.v-3,c.v-4 FILE=five_scalars
      57             : ```
      58             : 
      59             : or you can use five separate constant actions like this:
      60             : 
      61             : ```plumed
      62             : c1: CONSTANT VALUE=1
      63             : c2: CONSTANT VALUE=2
      64             : c3: CONSTANT VALUE=3
      65             : c4: CONSTANT VALUE=4
      66             : c5: CONSTANT VALUE=5
      67             : PRINT ARG=c1,c2,c3,c4,c5 FILE=five_scalars
      68             : ```
      69             : 
      70             : If you want to create a constant $2\times 3$ matrix you would use an input like the one below:
      71             : 
      72             : ```plumed
      73             : c: CONSTANT VALUES=1,2,3,4,5,6 NROWS=2 NCOLS=3
      74             : PRINT ARG=c FILE=constant_matrix
      75             : ```
      76             : 
      77             : The constant matrix that this action generates is as follows:
      78             : 
      79             : $$
      80             : M = \left(
      81             : \begin{matrix}
      82             : 1 & 2 & 3 \\
      83             : 4 & 5 & 6
      84             : \end{matrix}
      85             : \right)
      86             : $$
      87             : 
      88             : The print action ensures that the six elements of this constant matrix are output on every step.
      89             : 
      90             : Notice, that you can also read matrices from files by using a command like the one shown below:
      91             : 
      92             : ```plumed
      93             : #SETTINGS INPUTFILES=regtest/landmarks/rt-read-dissims/mymatrix.dat
      94             : c: CONSTANT FILE=regtest/landmarks/rt-read-dissims/mymatrix.dat NOLOG
      95             : PRINT ARG=c FILE=constant_matrix
      96             : ```
      97             : 
      98             : The `NOLOG` flag that is used in this example ensures that all the values read in from the input file are not output
      99             : in the plumed log file.
     100             : 
     101             : The CONSTANT  action is useful in combination with functions that take in input constants or parameters.
     102             : For example, the following input instructs plumed to compute the distance
     103             : between atoms 1 and 2. If this distance is between 1.0 and 2.0, it is
     104             : printed. If it is lower than 1.0 (larger than 2.0), 1.0 (2.0) is printed
     105             : 
     106             : ```plumed
     107             : cn: CONSTANT VALUES=1.0,2.0 SCALARS
     108             : dis: DISTANCE ATOMS=1,2
     109             : sss: SORT ARG=cn.v-0,dis,cn.v-1
     110             : PRINT ARG=sss.2
     111             : ```
     112             : 
     113             : By contrast this input only prints the distance between atom 1 and 2 if it is less than 1.
     114             : 
     115             : ```plumed
     116             : cn: CONSTANT VALUE=1.0
     117             : dis: DISTANCE ATOMS=1,2
     118             : sss: SORT ARG=cn,dis
     119             : PRINT ARG=sss.1
     120             : ```
     121             : 
     122             : Lastly, note that if you have an action that only takes constant values in input its output values will be treated as constants.  For example,
     123             : in the following input the values `d` and `f` are  evaluated on every step.  `c`, however, is only evaluated once during start up.
     124             : 
     125             : ```plumed
     126             : p: CONSTANT VALUE=1.0
     127             : c: CUSTOM ARG=p FUNC=2*x+1 PERIODIC=NO
     128             : d: DISTANCE ATOMS=1,2
     129             : f: CUSTOM ARG=p,d FUNC=x*y PERIODIC=NO
     130             : PRINT ARG=f FILE=colvar STRIDE=1
     131             : ```
     132             : 
     133             : */
     134             : //+ENDPLUMEDOC
     135             : 
     136             : namespace PLMD {
     137             : namespace generic {
     138             : 
     139             : class Constant : public ActionWithValue {
     140             : public:
     141             :   static void registerKeywords( Keywords& keys );
     142             :   explicit Constant(const ActionOptions&ao);
     143           0 :   void clearDerivatives( const bool& =false ) override {}
     144        6011 :   unsigned getNumberOfDerivatives() override {
     145        6011 :     return 0;
     146             :   }
     147           0 :   void calculate() override {}
     148           0 :   void apply() override {}
     149             : };
     150             : 
     151             : PLUMED_REGISTER_ACTION(Constant,"CONSTANT")
     152             : 
     153        1811 : void Constant::registerKeywords( Keywords& keys ) {
     154        1811 :   Action::registerKeywords(keys);
     155        1811 :   ActionWithValue::registerKeywords(keys);
     156        3622 :   keys.remove("NUMERICAL_DERIVATIVES");
     157        1811 :   keys.add("optional","FILE","an input file containing the matrix");
     158        1811 :   keys.add("compulsory","NROWS","0","the number of rows in your input matrix");
     159        1811 :   keys.add("compulsory","NCOLS","0","the number of columns in your matrix");
     160        1811 :   keys.add("optional","VALUE","the single number that you would like to store");
     161        1811 :   keys.add("optional","VALUES","the numbers that are in your constant value");
     162        1811 :   keys.add("compulsory","PERIODIC","NO","the domain of the values in your constant, the default implies that the constant is not periodic");
     163        1811 :   keys.addFlag("SCALARS",false,"treat the input list of numbers as a set of scalars");
     164        1811 :   keys.addFlag("NOLOG",false,"do not report all the read in scalars in the log");
     165        3622 :   keys.addOutputComponent("v","SCALARS","scalar","the # value");
     166        3622 :   keys.setValueDescription("scalar/vector/matrix","the constant value that was read from the plumed input");
     167        1811 : }
     168             : 
     169        1005 : Constant::Constant(const ActionOptions&ao):
     170             :   Action(ao),
     171        1005 :   ActionWithValue(ao) {
     172        1005 :   bool nolog=false;
     173        1005 :   parseFlag("NOLOG",nolog);
     174        1005 :   bool scalars=false;
     175             :   std::string fname, vname;
     176        1005 :   parse("FILE",fname);
     177        1005 :   std::vector<std::size_t> shape;
     178        1005 :   std::vector<double> vals;
     179        1005 :   if( fname.length()>0 ) {
     180           3 :     IFile mfile;
     181           3 :     mfile.open(fname);
     182             :     // Read in first line
     183           3 :     std::vector<std::string> words;
     184             :     unsigned nline=0;
     185           6 :     while( nline==0 ) {
     186           3 :       Tools::getParsedLine( mfile, words );
     187           3 :       nline=words.size();
     188             :     }
     189           3 :     std::vector<std::vector<double> > dissimilarities;
     190           3 :     if( nline==1 ) {
     191           0 :       shape.resize(1);
     192           0 :       error("invalid matrix in input file");
     193             :     }
     194           3 :     shape.resize(2);
     195           3 :     shape[1]=nline;
     196           3 :     std::vector<double> tmpdis( shape[1] );
     197          34 :     for(unsigned j=0; j<shape[1]; ++j) {
     198          31 :       Tools::convert( words[j], tmpdis[j] );
     199             :     }
     200           3 :     dissimilarities.push_back( tmpdis );
     201             : 
     202          31 :     while( Tools::getParsedLine( mfile, words ) ) {
     203          28 :       if( words.size()!=nline ) {
     204           0 :         error("bad formatting in matrix file");
     205             :       }
     206         360 :       for(unsigned j=0; j<nline; ++j) {
     207         332 :         Tools::convert( words[j], tmpdis[j] );
     208             :       }
     209          28 :       dissimilarities.push_back( tmpdis );
     210             :     }
     211           3 :     mfile.close();
     212           3 :     shape[0] = dissimilarities.size();
     213           3 :     vals.resize(shape[0]);
     214           3 :     if( shape.size()==2 ) {
     215           3 :       vals.resize( shape[0]*shape[1] );
     216             :     }
     217          34 :     for(unsigned i=0; i<shape[0]; ++i) {
     218         394 :       for(unsigned j=0; j<nline; ++j) {
     219         363 :         vals[i*nline+j] = dissimilarities[i][j];
     220             :       }
     221             :     }
     222           3 :   } else {
     223             :     std::size_t nr, nc;
     224        1002 :     parse("NROWS",nr);
     225        1002 :     parse("NCOLS",nc);
     226        1002 :     if( nr>0 && nc>0 ) {
     227          95 :       shape.resize(2);
     228          95 :       shape[0]=nr;
     229          95 :       shape[1]=nc;
     230          95 :       vals.resize( nr*nc );
     231          95 :       log.printf("  reading in %zu by %zu matrix \n", nr, nc );
     232         907 :     } else if( nr>0 || nc>0 ) {
     233           0 :       error("makes no sense to set only one of NROWS and NCOLS to a non-zero value");
     234             :     }
     235        1002 :     parseVector("VALUES",vals);
     236        2004 :     parseFlag("SCALARS",scalars);
     237        1002 :     if( vals.size()==0 ) {
     238         162 :       parseVector("VALUE",vals);
     239          81 :       if( vals.size()!=1 ) {
     240           0 :         error("VALUE keyword should take a single scalar");
     241             :       }
     242         921 :     } else if( vals.size()==1 ) {
     243         226 :       scalars=false;
     244             :     }
     245             : 
     246        1002 :     log.printf("  read in %zu values :", vals.size() );
     247        1002 :     if( !nolog ) {
     248       33206 :       for(unsigned i=0; i<vals.size(); ++i) {
     249       32700 :         log.printf(" %f", vals[i] );
     250             :       }
     251             :     }
     252        1002 :     log.printf("\n");
     253        1002 :     if( !scalars && shape.size()==0 && vals.size()>1 ) {
     254         599 :       shape.resize(1);
     255         599 :       shape[0] = vals.size();
     256             :     }
     257             :   }
     258        1005 :   std::vector<std::string> domain(2);
     259        1005 :   parseVector("PERIODIC",domain);
     260        1005 :   if( !scalars ) {
     261             :     // Now set the value
     262        1004 :     addValue( shape );
     263        1004 :     if( domain[0]!="NO" ) {
     264           0 :       setPeriodic( domain[0], domain[1] );
     265             :     } else {
     266        1004 :       setNotPeriodic();
     267             :     }
     268        1004 :     getPntrToComponent(0)->setConstant();
     269     1629551 :     for(unsigned i=0; i<vals.size(); ++i) {
     270     1628547 :       getPntrToComponent(0)->set( i, vals[i] );
     271             :     }
     272             :   } else {
     273           1 :     if( domain[0]!="NO") {
     274           0 :       error("use multiple CONSTANT commands to create scalar constants with a periodic domain");
     275             :     }
     276           3 :     for(unsigned i=0; i<vals.size(); i++) {
     277             :       std::string num;
     278           2 :       Tools::convert(i,num);
     279           4 :       addComponent("v-"+num);
     280           2 :       componentIsNotPeriodic("v-"+num);
     281           2 :       Value* comp=getPntrToComponent("v-"+num);
     282           2 :       comp->setConstant();
     283           2 :       comp->set(vals[i]);
     284             :     }
     285             :   }
     286        2010 : }
     287             : 
     288             : }
     289             : }
     290             : 

Generated by: LCOV version 1.16