LCOV - code coverage report
Current view: top level - valtools - VStack.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 100 108 92.6 %
Date: 2025-04-08 18:07:56 Functions: 9 10 90.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2014-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 "core/ActionWithMatrix.h"
      23             : #include "core/ActionRegister.h"
      24             : 
      25             : //+PLUMEDOC MCOLVAR VSTACK
      26             : /*
      27             : Create a matrix by stacking vectors together
      28             : 
      29             : This action takes 2 or more vectors with the same number of elements as input and outputs a matrix.
      30             : This output matrix is constructed stacking the input vectors vertically.  The first row of the output
      31             : matrix thus contains the first elements of all the input vector, the second row contains the second elements
      32             : and so on.  In other words, the first input vector is in the first column of the output matrix, the second
      33             : input vector is in the second column and so.
      34             : 
      35             : The following shows an example of how this action operates in practise. The [DISTANCE](DISTANCE.md) command below calculates
      36             : the vectors containing four pairs of atoms.  The VSTACK command is then used to construct a $4 \times 3$ matrix
      37             : that contains all the vectors. The 1,1, 1,2 and 1,3 components in this matrix contain the
      38             : $x$, $y$ and $z$ components of the vector connecting atoms 1 and 2. The 2,1, 2,2 and 2,3 contain the
      39             : $x$, $y$ and $z$ components of the vector connecting atoms 3 and 4 and so on.
      40             : 
      41             : ```plumed
      42             : d1: DISTANCE ...
      43             :    COMPONENTS
      44             :    ATOMS1=1,2 ATOMS2=3,4
      45             :    ATOMS3=5,6 ATOMS4=7,8
      46             : ...
      47             : m: VSTACK ARG=d1.x,d1.y,d1.z
      48             : 
      49             : PRINT ARG=m FILE=matrix.dat
      50             : ```
      51             : 
      52             : */
      53             : //+ENDPLUMEDOC
      54             : 
      55             : namespace PLMD {
      56             : namespace valtools {
      57             : 
      58             : class VStack : public ActionWithMatrix {
      59             : private:
      60             :   std::vector<bool> stored;
      61             : public:
      62             :   static void registerKeywords( Keywords& keys );
      63             : /// Constructor
      64             :   explicit VStack(const ActionOptions&);
      65             : /// Get the number of derivatives
      66         294 :   unsigned getNumberOfDerivatives() override {
      67         294 :     return 0;
      68             :   }
      69             : ///
      70             :   void prepare() override ;
      71             : ///
      72     1270505 :   unsigned getNumberOfColumns() const override {
      73     1270505 :     return getNumberOfArguments();
      74             :   }
      75             : ///
      76             :   void setupForTask( const unsigned& task_index, std::vector<unsigned>& indices, MultiValue& myvals ) const override ;
      77             : ///
      78             :   void performTask( const std::string& controller, const unsigned& index1, const unsigned& index2, MultiValue& myvals ) const override ;
      79             : ///
      80             :   void runEndOfRowJobs( const unsigned& ival, const std::vector<unsigned> & indices, MultiValue& myvals ) const override ;
      81             : ///
      82             :   void getMatrixColumnTitles( std::vector<std::string>& argnames ) const override ;
      83             : };
      84             : 
      85             : PLUMED_REGISTER_ACTION(VStack,"VSTACK")
      86             : 
      87         254 : void VStack::registerKeywords( Keywords& keys ) {
      88         254 :   ActionWithMatrix::registerKeywords( keys );
      89         508 :   keys.addInputKeyword("compulsory","ARG","scalar/vector","the values that you would like to stack together to construct the output matrix");
      90         508 :   keys.setValueDescription("matrix","a matrix that contains the input vectors in its columns");
      91         254 : }
      92             : 
      93         139 : VStack::VStack(const ActionOptions& ao):
      94             :   Action(ao),
      95         139 :   ActionWithMatrix(ao) {
      96         139 :   if( getNumberOfArguments()==0 ) {
      97           0 :     error("no arguments were specificed");
      98             :   }
      99         139 :   if( getPntrToArgument(0)->getRank()>1 ) {
     100           0 :     error("all arguments should be vectors");
     101             :   }
     102             :   unsigned nvals=1;
     103             :   bool periodic=false;
     104             :   std::string smin, smax;
     105         139 :   if( getPntrToArgument(0)->getRank()==1 ) {
     106         119 :     nvals = getPntrToArgument(0)->getShape()[0];
     107             :   }
     108         139 :   if( getPntrToArgument(0)->isPeriodic() ) {
     109             :     periodic=true;
     110          24 :     getPntrToArgument(0)->getDomain( smin, smax );
     111             :   }
     112             : 
     113        1228 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     114        1089 :     if( getPntrToArgument(i)->getRank()>1 || (getPntrToArgument(i)->getRank()==1 && getPntrToArgument(i)->hasDerivatives()) ) {
     115           0 :       error("all arguments should be vectors");
     116             :     }
     117        1089 :     if( getPntrToArgument(i)->getRank()==0 ) {
     118          41 :       if( nvals!=1 ) {
     119           0 :         error("all input vector should have same number of elements");
     120             :       }
     121        1048 :     } else if( getPntrToArgument(i)->getShape()[0]!=nvals ) {
     122           0 :       error("all input vector should have same number of elements");
     123             :     }
     124        1089 :     if( periodic ) {
     125          51 :       if( !getPntrToArgument(i)->isPeriodic() ) {
     126           0 :         error("one argument is periodic but " + getPntrToArgument(i)->getName() + " is not periodic");
     127             :       }
     128             :       std::string tmin, tmax;
     129          51 :       getPntrToArgument(i)->getDomain( tmin, tmax );
     130          51 :       if( tmin!=smin || tmax!=smax ) {
     131           0 :         error("domain of argument " + getPntrToArgument(i)->getName() + " is different from domain for all other arguments");
     132             :       }
     133        1038 :     } else if( getPntrToArgument(i)->isPeriodic() ) {
     134           0 :       error("one argument is not periodic but " + getPntrToArgument(i)->getName() + " is periodic");
     135             :     }
     136             :   }
     137             :   // And create a value to hold the matrix
     138         139 :   std::vector<unsigned> shape(2);
     139         139 :   shape[0]=nvals;
     140         139 :   shape[1]=getNumberOfArguments();
     141         139 :   addValue( shape );
     142         139 :   if( periodic ) {
     143          24 :     setPeriodic( smin, smax );
     144             :   } else {
     145         115 :     setNotPeriodic();
     146             :   }
     147             :   // And store this value
     148         139 :   getPntrToComponent(0)->buildDataStore();
     149         139 :   getPntrToComponent(0)->reshapeMatrixStore( shape[1] );
     150             :   // Setup everything so we can build the store
     151         139 :   done_in_chain=true;
     152         139 :   ActionWithVector* av=dynamic_cast<ActionWithVector*>( getPntrToArgument(0)->getPntrToAction() );
     153         139 :   if( av ) {
     154          99 :     const ActionWithVector* head0 = av->getFirstActionInChain();
     155         996 :     for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     156         928 :       ActionWithVector* avv=dynamic_cast<ActionWithVector*>( getPntrToArgument(i)->getPntrToAction() );
     157         928 :       if( !avv ) {
     158           4 :         continue;
     159             :       }
     160         924 :       if( head0!=avv->getFirstActionInChain() ) {
     161          31 :         done_in_chain=false;
     162          31 :         break;
     163             :       }
     164             :     }
     165             :   } else {
     166          40 :     done_in_chain=false;
     167             :   }
     168         139 :   unsigned nder = buildArgumentStore(0);
     169             :   // This checks which values have been stored
     170         139 :   stored.resize( getNumberOfArguments() );
     171         139 :   std::string headstr=getFirstActionInChain()->getLabel();
     172        1228 :   for(unsigned i=0; i<stored.size(); ++i) {
     173        1089 :     stored[i] = getPntrToArgument(i)->ignoreStoredValue( headstr );
     174             :   }
     175         139 : }
     176             : 
     177          23 : void VStack::getMatrixColumnTitles( std::vector<std::string>& argnames ) const {
     178          60 :   for(unsigned j=0; j<getNumberOfArguments(); ++j) {
     179          37 :     if( (getPntrToArgument(j)->getPntrToAction())->getName()=="COLLECT" ) {
     180          17 :       ActionWithArguments* aa = dynamic_cast<ActionWithArguments*>( getPntrToArgument(j)->getPntrToAction() );
     181          17 :       plumed_assert( aa && aa->getNumberOfArguments()==1 );
     182          17 :       argnames.push_back( (aa->getPntrToArgument(0))->getName() );
     183             :     } else {
     184          20 :       argnames.push_back( getPntrToArgument(j)->getName() );
     185             :     }
     186             :   }
     187          23 : }
     188             : 
     189        3100 : void VStack::prepare() {
     190        3100 :   ActionWithVector::prepare();
     191        3100 :   if( getPntrToArgument(0)->getRank()==0 || getPntrToArgument(0)->getShape()[0]==getPntrToComponent(0)->getShape()[0] ) {
     192        3082 :     return ;
     193             :   }
     194          18 :   std::vector<unsigned> shape(2);
     195          18 :   shape[0] = getPntrToArgument(0)->getShape()[0];
     196          18 :   shape[1] = getNumberOfArguments();
     197          18 :   getPntrToComponent(0)->setShape(shape);
     198          18 :   getPntrToComponent(0)->reshapeMatrixStore( shape[1] );
     199             : }
     200             : 
     201      214418 : void VStack::setupForTask( const unsigned& task_index, std::vector<unsigned>& indices, MultiValue& myvals ) const {
     202      214418 :   unsigned nargs = getNumberOfArguments();
     203      214418 :   unsigned nvals = getConstPntrToComponent(0)->getShape()[0];
     204      214418 :   if( indices.size()!=nargs+1 ) {
     205       51622 :     indices.resize( nargs+1 );
     206             :   }
     207     4287565 :   for(unsigned i=0; i<nargs; ++i) {
     208     4073147 :     indices[i+1] = nvals + i;
     209             :   }
     210             :   myvals.setSplitIndex( nargs + 1 );
     211      214418 : }
     212             : 
     213     4073147 : void VStack::performTask( const std::string& controller, const unsigned& index1, const unsigned& index2, MultiValue& myvals ) const {
     214     4073147 :   unsigned ind2 = index2;
     215     4073147 :   if( index2>=getConstPntrToComponent(0)->getShape()[0] ) {
     216     4073147 :     ind2 = index2 - getConstPntrToComponent(0)->getShape()[0];
     217             :   }
     218     4073147 :   myvals.addValue( getConstPntrToComponent(0)->getPositionInStream(), getArgumentElement( ind2, index1, myvals ) );
     219             : 
     220     4073147 :   if( doNotCalculateDerivatives() ) {
     221      380548 :     return;
     222             :   }
     223     3692599 :   addDerivativeOnVectorArgument( stored[ind2], 0, ind2, index1, 1.0, myvals );
     224             : }
     225             : 
     226      214418 : void VStack::runEndOfRowJobs( const unsigned& ival, const std::vector<unsigned> & indices, MultiValue& myvals ) const {
     227      214418 :   if( doNotCalculateDerivatives() || !matrixChainContinues() ) {
     228             :     return ;
     229             :   }
     230             : 
     231           3 :   unsigned nmat = getConstPntrToComponent(0)->getPositionInMatrixStash(), nmat_ind = myvals.getNumberOfMatrixRowDerivatives( nmat );
     232             :   std::vector<unsigned>& matrix_indices( myvals.getMatrixRowDerivativeIndices( nmat ) );
     233           3 :   plumed_assert( nmat_ind<matrix_indices.size() );
     234          12 :   for(unsigned i=0; i<getNumberOfArguments(); ++i) {
     235             :     bool found=false;
     236           9 :     ActionWithValue* iav = getPntrToArgument(i)->getPntrToAction();
     237           9 :     for(unsigned j=0; j<i; ++j) {
     238           6 :       if( iav==getPntrToArgument(j)->getPntrToAction() ) {
     239             :         found=true;
     240             :         break;
     241             :       }
     242             :     }
     243           9 :     if( found ) {
     244           6 :       continue ;
     245             :     }
     246             : 
     247             :     unsigned istrn = getPntrToArgument(i)->getPositionInStream();
     248          48 :     for(unsigned k=0; k<myvals.getNumberActive(istrn); ++k) {
     249          45 :       matrix_indices[nmat_ind] = myvals.getActiveIndex(istrn,k);
     250          45 :       nmat_ind++;
     251             :     }
     252             :   }
     253             :   myvals.setNumberOfMatrixRowDerivatives( nmat, nmat_ind );
     254             : }
     255             : 
     256             : }
     257             : }

Generated by: LCOV version 1.16